SP5971 LCMSUM - LCM Sum
SP5971 LCMSUM - LCM Sum
题意
- 求\(\sum_{i=1}^nlcm(i,n)\).
- 数据范围:\(T\leq 300000,n\leq 1000000\).
思路
首先知道\(lcm(i,n)=\frac{i*n}{gcd(i,n)}\),所以有原式:
\[n\sum_{i=1}^n\frac{i}{gcd(i,n)}
\]
一般到这里都要枚举一下\(gcd(i,n)\)。
\[n\sum_{d|n}\sum_{i=1}^n\frac{i}{d}[gcd(i,n)=d]
\]
\(gcd(i,n)=d\),那么必然有\(i\)是\(d\)的倍数。
所以枚举\(id\)
\[n\sum_{d|n}\sum_{i=1}^\frac{n}{d}i[gcd(i,n/d)=1]\\
\]
已知
\[\sum_{i=1}^ni[gcd(i,n)=1]=\frac{\varphi(n)*n}{2}
\]
转换一下:
\[n\sum_{d|n}\frac{\varphi(\frac{n}{d})\frac{n}{d}}{2}
\]
\(d\)和\(\frac{n}{d}\)都是成对出现的,所以再改一下:
\[n\sum_{d|n}\frac{\varphi(d)d}{2}
\]
这里由于询问特别大,不能每次都枚举约数。
所以用倍数法预处理出所有答案。
时间复杂度为n乘一个到n的调和级数求和,大概在\(nlnn\)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
int n;
int phi[maxn], primes[maxn], cnt;
ll ans[maxn];
bool vis[maxn];
void get_eulers(int n)
{
phi[1] = 1;
for(int i = 2; i <= n; i++)
{
if(!vis[i])
{
primes[++cnt] = i;
phi[i] = i-1;
}
for(int j = 1; primes[j] <= n/i; j++)
{
vis[primes[j]*i] = 1;
if(i % primes[j] == 0)
{
phi[primes[j]*i] = phi[i]*primes[j];
break;
}
else phi[primes[j]*i] = phi[i]*(primes[j]-1);
}
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n/i; j++)
ans[i*j] += 1ll*j*phi[j]/2;
for(ll i = 1; i <= n; i++)
ans[i] = ans[i]*i+i;
}
inline void solve()
{
scanf("%d", &n);
printf("%lld\n", ans[n]);
}
int main()
{
get_eulers(maxn-5);
int T; scanf("%d", &T);
while(T--) solve();
return 0;
}