SPOJ5971 LCMSUM - LCM Sum

https://www.spoj.com/problems/LCMSUM/

\[\begin{aligned} ans&=\sum_{i=1}^nlcm(i,n) \\ &=\sum_{i=1}^n \frac{i*n}{gcd(i,n)} \\ &=\sum_{d=1}^n\sum_{i=1}^n[gcd(i,n)=d]\frac{i*n}{gcd(i,n)} \\ &=\sum_{d=1}^n\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}[gcd(i,\frac{n}{d})=1] i*n \\ &=n*\sum_{d=1}^n\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}[gcd(i,\frac{n}{d})=1] i \\ &=n*\sum_{d=1}^n\sum_{i=1}^d[gcd(i,d)=1] i \\ \end{aligned} \]

\[f(i)=\sum_{i=1}^d[gcd(i,d)=1]i \]

\[ans=n*\sum_{d=1}^nf(d) \]

如果我们求出了所有的\(f(d)\),那么枚举d,让d,2d,3d……kd 都加上这个\(f(d)\),最后各自再乘上自己,就算完了。这个复杂度是\(nlog_2n\)

\(f(i)\)怎么算?
我们发现\(f(i)\)就是所有与小于等于\(i\)且与\(i\)互质的数的和
\(f(1)=1\)
\(i>1\)时,\(f(i)=\phi(i)*i/2\),因为\(gcd(j,i)=gcd(i-j,i)\),即与\(i\)互质的数成对出现,且每一对相加等于\(i\)

#include<bits/stdc++.h>

using namespace std;

#define N 1000001

int phi[N],prime[N],cnt;
bool check[N]; 

long long ans[N];

void euler()
{
    phi[1]=1;
    for(int i=2;i<=N;i++)
    {
        if(!check[i])
        {
            prime[++cnt]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=cnt;j++)
        {
            if(i*prime[j]>=N) break;
            check[i*prime[j]]=true;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
}

void pre()
{
	for(int i=2;i<N;++i)
		for(int j=i;j<N;j+=i)
			ans[j]+=1ll*i*phi[i]/2;
	for(int i=1;i<N;++i) ans[i]++;
	for(int i=1;i<N;++i) ans[i]*=i;
}

int main()
{
	euler();
	pre();
	int T,n;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		printf("%lld\n",ans[n]); 
	}
}
posted @ 2021-08-10 11:10  TRTTG  阅读(50)  评论(0)    收藏  举报