BZOJ.2705.[SDOI2012]Longge的问题(莫比乌斯反演 欧拉函数)

题目链接

(Description)

  求$$sum_{i=1}^ngcd(i,n)$$

(Solution)

[ egin{aligned} sum_{i=1}^ngcd(i,n) &=sum_{d=1}^ndsum_{i=1}^n[gcd(i,n)=d]\ &=sum_{d=1}^ndsum_{i=1}^{lfloorfrac{n}{d} floor}[gcd(i,lfloorfrac{n}{d} floor)=1] end{aligned} ]

  后一项不需要再化了,因为就是(phi(lfloorfrac{n}{d} floor))
  所以

[sum_{i=1}^ngcd(i,n)=sum_{d=1}^nd*phi(lfloorfrac{n}{d} floor) ]

  因为(gcd(i,n)mid n),所以

[ egin{aligned} sum_{i=1}^ngcd(i,n) &=sum_{d=1}^nd*phi(lfloorfrac{n}{d} floor)\ &=sum_{dmid n}d*phi(lfloorfrac{n}{d} floor) end{aligned} ]

  约数可以(O(sqrt{n}))枚举,(phi)可以(O(sqrt{n}))求,复杂度为(因子个数*sqrt{n})

//928kb	56ms
//注意d!
#include <cmath>
#include <cstdio>
typedef long long LL;
const int N=1<<16;

int cnt,P[N>>3];
LL n;
bool Not_p[N+3];

void Make_Table(int N)
{
	for(int i=2; i<=N; ++i)
	{
		if(!Not_p[i]) P[++cnt]=i;
		for(int j=1; j<=cnt&&i*P[j]<=N; ++j)
		{
			Not_p[i*P[j]]=1;
			if(!(i%P[j])) break;
		}
	}
}
LL Phi(LL x)
{
	LL res=1;
	for(int i=1; i<=cnt&&1ll*P[i]*P[i]<=x; ++i)
		if(!(x%P[i]))
		{
			x/=P[i], res*=(P[i]-1);
			while(!(x%P[i])) x/=P[i], res*=P[i];
		}
	if(x>1) res*=x-1;
	return res;
}

int main()
{
	scanf("%lld",&n);
	Make_Table(sqrt(n)+1);
	LL res=0;
	int lim=sqrt(n);
	for(int i=1,lim=sqrt(n); i<=lim; ++i)
		if(!(n%i)) res+=1ll*i*Phi(n/i)+1ll*(n/i)*Phi(i);//!
	if(1ll*lim*lim==n) res-=lim*Phi(lim);
	printf("%lld",res);

	return 0;
}
原文地址:https://www.cnblogs.com/SovietPower/p/8745879.html