[SDOI2012] Longge 的问题

题目传送门

给定一个整数 \(n\),你需要求出 \(\sum\limits_{i=1}^n \gcd(i, n)\),其中 \(\gcd(i, n)\) 表示 \(i\)\(n\) 的最大公因数。

样例输入

6

样例输出

15

数据规模与约定

  • 对于 $60% $ 的数据,保证 \(n\leq 2^{16}\)
  • 对于 $100% $ 的数据,保证 \(1\leq n< 2^{32}\)
好一个龙哥 (龙哥就是龙!) 热知识:\(2^{32}=4,294,967,296\)

不难看出,\(gcd(i,n)|n\)。即\(gcd(i,n)\in \lbrace d \rbrace\)。可以以\(O(\sqrt n)\)时间复杂度枚举\(n\)的因数\(d\)
对于每个\(d\),我们寻找有多少\(gcd(i,n)=d \leftrightarrow gcd(\frac{d}{i},\frac{d}{n})=1\),易知此数量为\(\phi(n/d)\)
故$$ans=\sum\limits_{d|n}d*\phi(\frac{d}{i})$$

#include<cstdio>
typedef unsigned long long ll;
inline ll phi(ll x){
	//printf("phi%d=",x);
	ll ret=x;
	for(ll i=2;i*i<=x;++i){
			if(x%i==0)ret=ret/i*(i-1);
			while(x%i==0)x/=i;
		}
	if(x>1)ret=ret/x*(x-1);
	//printf("%d\n",ret);
	return ret;
}
int main(){
	ll n,ans=0,d=1;
	scanf("%llu",&n);
	for(;d*d<n;++d)
		if(n%d==0)
			ans+=d*phi(n/d)+n/d*phi(d);
	if(d*d==n)ans+=d*phi(d);
	printf("%llu",ans);
	return 0;
}

一个容易写错的地方

ans+=d*phi(n/d)+n/d*phi(d);

我一直把它写成\(d*\phi(d)+\frac{d}{n}*\phi(d)\) 排bug排了好久,总是怀疑别的部分写错了,始终没有怀疑过这一行

另外

if(d*d==n)ans+=d*phi(d);

需要单独拿出来以免被加两次 真高兴我在自己排bug的时候就想起了这一点并且改了

具体怎么把这个东西想出来,,我可能后续发布在评论区等等。唉。
附一张手记

posted @ 2022-09-14 23:00  全球通u1  阅读(17)  评论(0编辑  收藏  举报