BZOJ2226 [Spoj 5971] LCMSum

题意

给定\(n(n \leq 10^6)\),求
\[ \sum_{i=1}^{n} \textrm{lcm}(i,n) \]
\(T(T \leq 3 \times 10^5)\)组询问。

分析

\[ \sum_{i=1}^{n}\textrm{lcm}(i,n) \\ =\sum_{i=1}^{n}\frac{i \cdot n}{\gcd(i,n)}\\ =n \sum_{d|n}\frac{1}{d}\sum_{i=1}^{n}[\gcd(i,n)=d] \cdot i\\ =n \sum_{d|n}\frac{1}{d}\sum_{i=1}^{\frac{n}{d}}[\gcd(i,\frac{n}{d})=1] \cdot i \cdot d \\ = n \sum_{d|n} \sum_{i=1}^{\frac{n}{d}} [\gcd(i,\frac{n}{d})=1] \cdot i \]
后半部分参照这里,可得
\[ 原式 =n \sum_{d|n} \frac{(\varphi(n) + e(n)) \cdot n}{2} \\ =\frac{n}{2} \sum_{d|n} (\varphi(n) + e(n)) \cdot n \]
现在的这个后面的式子\(O(n)\)线性筛后,枚举倍数\(O(n \ln n)\)预处理。

然后就能\(O(1)\)回答每次询问。

时间复杂度\(O(n + n \ln n + T)\)

参照Sengxian

代码

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#include<cassert>
#define rg register
#define il inline
#define co const
#pragma GCC optimize ("O0")
using namespace std;
template<class T> il T read()
{
    rg T data=0;
    rg int w=1;
    rg char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=10*data+ch-'0',ch=getchar();
    return data*w;
}
template<class T> il T read(rg T&x)
{
    return x=read<T>();
}
typedef long long ll;
co int INF=0x7fffffff;

co int MAXN=1e6+7;
int prime[MAXN],pcnt;
int phi[MAXN];
ll f[MAXN];

void linear()
{
    prime[1]=1;
    phi[1]=1;
    for(int i=2;i<MAXN;++i)
    {
        if(!prime[i])
        {
            prime[++pcnt]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=pcnt&&i*prime[j]<MAXN;++j)
        {
            prime[i*prime[j]]=1;
            phi[i*prime[j]]=phi[i]*phi[prime[j]];
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
        }
    }
    for(int i=1;i<MAXN;++i)
        for(int j=i;j<MAXN;j+=i)
            f[j]+=(ll)phi[i]*i;
}

ll solve(int n)
{
    return (f[n]+1)*n/2;
}

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    linear();
    int T=read<int>();
    while(T--)
    {
        printf("%lld\n",solve(read<int>()));
    }
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/9892650.html