题目链接:http://poj.org/problem?id=2480
题意:计算Σgcd(i,n) ,1<=i<=n。
思路:这题与51nod 1040是一样的题目。
每一项都是n的因子,我们要求的就是每个因子v的个数。
可以转换成求gcd(i/v,n/v)=1个数 (i/v是0~n/v ) n/v也是n的因数
答案就是sum(p*phi(n/p))了(p是因子,phi()是欧拉函数,sum是求和)。但是数据比较大,用因子乘欧拉函数会超时。
这里要用到积性函数的一点知识。因为gcd(i,m*n)是积性函数(gcd(i,n*m)=gcd(i,n)*gcd(i,m),证明百度。。。)
令f(n)=Σgcd(i,n)=sum(p*phi(n/p))。
积性函数很容易想到用素因子分解,因为素因子求解是容易的,那么令n=p1k1*p2k2*..*pmkm
首先就是要求到 f(pr), 因为pr的因子为1,p,p2,p3..pr。
所以 f(pr)= 1*(pr-pr-1) +p*(pr-1-pr-2)+p2*(pr-2-pr-3)+...+pr-1(p-1) +pr*1
=(pr-pr-1)+(pr-pr-1)+...+(pr-pr-1)+pr
= r*(pr-pr-1)+pr= (r+1)*pr-r*pr-1
f(n)=f(p1k1)*f(p2k2)*...*f(pmkm)
这样我们就可以根据素因子分解,对每个素因子求解再相乘即可。
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; int main() { ll n; while(cin>>n) { ll ans=1; for(ll i=2;i*i<=n;i++)//素因子分解,类似于欧拉函数 { if(n%i==0) { ll r=0,x=1;//r记录该素因子的次方,x=p^r while(n%i==0) { n/=i; x*=i; r++; } ans*=(r+1)*x-r*(x/i);//代入上面所求公式 } } if(n>1)//类似于欧拉函数处理,多了最后一个大于根号n的素因子,一样代入公式 ans*=2*n-1; cout<<ans<<endl; } return 0; }