题意
给定\(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;
}