LCMSum bzoj-2226 Spoj-5971
题目大意:求$sumlimits_{i=1}^nlcm(i,n)$
注释:$1le nle 10^6$,$1le cases le 3cdot 10^5$。
想法:$sumlimits_{i=1}^nlcm(i,n)$
$=sumlimits_{i=1}^nfrac{in}{gcd(i,n)}$
$=ncdot sumlimits_{i=1}^n frac{i}{gcd(i,n)}$
$=ncdot sumlimits_{d=1}^nsumlimits_{i=1}^{n}i/d[gcd(i,n)=d]$
$=ncdot sumlimits_{d|n}sumlimits_{i=1}^{frac{n}{d}}i[gcd(i,frac{n}{d})=1]$
$=ncdot sumlimits_{d|n}sumlimits_{i=1}^{d}i[gcd(i,d)=1]$
$=ncdot sumlimits_{d|n}frac{varphi(d)cdot d}2$
$=n/2cdot sumlimits_{d|n}varphi(d)cdot d$
令$f(n)=varphi(n)cdot n$。显然是一个积性函数。所以$sumlimits_{d|n}f(d)$是一个积性函数。所以可以线筛。
最后,附上丑陋的代码... ...
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1000010
using namespace std;
typedef long long ll;
const int m=1000000;
int phi[N],prime[N],tot;
ll f[N];
bool np[N];
int main()
{
int cases,n;
for(int i=2;i<=m;i++)
{
if(!np[i]) phi[i]=i-1,prime[++tot]=i;
for(int j=1;j<=tot&&i*prime[j]<=m;j++)
{
np[i*prime[j]]=1;
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for(int i=2;i<=m;i++)
{
for(int j=i;j<=m;j+=i)
{
f[j]+=(ll)i*phi[i]/2;
}
}
scanf("%d",&cases);
while(cases--)scanf("%d",&n),printf("%lld
",(f[n]+1)*n);
return 0;
}
小结:这种题推式子就好了啊qwq。