题目链接:http://poj.org/problem?id=2480
题目大意:求一个数n的gcd(i,n)求和(i从1到n)
思路:
设函数g(n) = gcd(i,n) (1<=i<=n),由积性函数的定义,g(n)=g(m1)*g(m2) (n=m1*m2 且 (m1, m2)= 1),所以g是积性函数。由具体数学上的结论,积性函数的和也是积性的。所以f(n) = ∑gcd(i, n)也是积性函数。由初等数论中的定理,如果f(n)是不恒为0的数论函数,n>1时 n=p1^a1*p2^a2*...*ps^as,那么f(n)是积性函数的充要条件是f(1)=1,及f(n) = f(p1^a1)*f(p2^a2)*...f(pr^ar)。所以只要求f(pi^ai)就好,如果d是n的一个约数,那么1<=i<=n中gcd(i,n) = d的个数是phi(n/d),即n/d的欧拉函数
求出来的公式参考这个博客:https://blog.youkuaiyun.com/qq_41515833/article/details/95961608
先唯一分解,再直接利用这个公式,ac!
ac代码:
#include<iostream>
#include<cstring>
#include<algorithm>
typedef long long ll;
using namespace std;
ll poww(ll a,ll b) {
ll ans = 1, base = a;
while (b != 0) {
if (b & 1 != 0)
ans *= base;
base *= base;
b >>= 1;
}
return ans;
}
struct node{
ll p;
ll m;
}su[105];
int main(){
ll n;
while(cin>>n){
ll ans=1;
ll cnt=0;
//唯一分解
for(ll i=2;i*i<=n;i++){
if(n==1)
break;
if(n%i==0){
su[cnt].p=i;
su[cnt].m=0;
while(n%i==0){
n/=i;
su[cnt].m++;
}
cnt++;
}
}
if(n!=1){
su[cnt].p=n;
su[cnt].m=1;
cnt++;
}
ll t;
for(int i=0;i<cnt;i++){
t=su[i].m*(poww(su[i].p,su[i].m)-poww(su[i].p,su[i].m-1))+poww(su[i].p,su[i].m);
ans*=t;
}
cout<<ans<<endl;
}
return 0;
}