P1891 疯狂 LCM
疯狂 LCM
题意即求:
\[\sum _ { i = 1 } ^ { n } \operatorname{lcm} ( i , n )
\]
其中 \(T\le 3 \times 10 ^5\),\(n \le 10 ^ 6\)。
直接推导:
\[\begin{aligned}
&
\sum _ { i = 1 } ^ { n } \operatorname{lcm} ( i , n )
\\
= &
\sum _ { i = 1 } ^ { n } \dfrac{ i n }{\gcd ( i , n )}
\\
= &
\sum _ {d \mid n } n\sum _ { i = 1 } ^ { n } \dfrac{ i }{ d } \left[ \gcd ( i , n ) = d \right]
\\
= &
\sum _ {d \mid n } n\sum _ { i = 1 } ^ { n / d } i \left[ \gcd ( i , n / d ) = 1 \right]
\\
= &
\sum _ {d \mid n } n\sum _ { i = 1 } ^ { n / d } i \sum _ { k \mid i , k \mid n/d} \mu ( k )
\\
= &
n\sum _ {d \mid n } \sum _ { k \mid n/d} \mu ( k ) k \sum _ { i = 1 } ^ { n / kd } i
\\
= &
n\sum _ {T \mid n } \sum _ { d \mid T } \mu ( k ) k \sum _ { i = 1 } ^ { n / T } i
\end{aligned}
\]
后面整体都可以 \(O( n \ln n )\) 预处理。
时间复杂度 \(O(n \ln n + T)\)。
代码:
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
namespace Ehnaev{
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();}
while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();}
return ret*f;
}
inline void write(ll x) {
static char buf[22];static ll len=-1;
if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);}
else {putchar(45);do{buf[++len]=-(x%10)+48;x/=10;}while(x);}
while(len>=0) putchar(buf[len--]);
}
}using Ehnaev::read;using Ehnaev::write;
inline void writeln(ll x) {write(x);putchar(10);}
const ll N=1e6;
ll T,n,cnt;
ll prime[N+5],f[N+5],mu[N+5],g[N+5],ans[N+5];
bool ff[N+5];
inline void Init() {
ff[1]=1;mu[1]=1;
for(ll i=2;i<=N;i++) {
if(!ff[i]) {prime[++cnt]=i;mu[i]=-1;}
for(ll j=1;j<=cnt&&i*prime[j]<=N;j++) {
ff[i*prime[j]]=1;
if(i%prime[j]==0) {mu[i*prime[j]]=0;break;}
mu[i*prime[j]]=-mu[i];
}
}
for(ll i=1;i<=N;i++) {f[i]=i*mu[i];}
for(ll i=1;i<=cnt;i++) {
for(ll j=1;j*prime[i]<=N;j++) {
f[j*prime[i]]+=f[j];
}
}
for(ll i=1;i<=N;i++) {g[i]=i*(i+1)/2;}
for(ll i=1;i<=N;i++) {
for(ll j=i,cn=1;j<=N;j+=i,cn++) {
ans[j]+=f[i]*g[cn];
}
}
for(ll i=1;i<=N;i++) ans[i]*=i;
}
int main() {
T=read();Init();
while(T--) {
n=read();
writeln(ans[n]);
}
return 0;
}