Bzoj2705 Longge的问题
Time Limit: 3000MS | Memory Limit: 131072KB | 64bit IO Format: %lld & %llu |
Description
Longge的数学成绩非常好,并且他非常乐于挑战高难度的数学问题。现在问题来了:给定一个整数N,你需要求出∑gcd(i, N)(1<=i <=N)。
Input
一个整数,为N。
Output
一个整数,为所求的答案。
Sample Input
6
Sample Output
15
Hint
【数据范围】
对于60%的数据,0<N<=2^16。
对于100%的数据,0<N<=2^32。
Source
SDOI2012
求Σgcd(i,n) (1<=i<=n)
暴力枚举当然可行,但是TLE不可避。
考虑转化问题,从1到n的范围内,有许多个i的gcd(i,n)等于同一个n的因数。我们可以枚举n的每一个因数k,累计“以该数k为解的gcd(i,n)的个数s(k)"乘以该数,就能得到答案。
若有gcd(n,m)=k,那么n和m同除公约数k后,可以得到gcd(n/k,m/k)=1。由前式可知(m/k)与(n/k)互质。满足条件的(m/k)个数,也就是s(k)就等于phi(n/k) ←欧拉函数!
解1:直接套模板。算法无误,但是因为题目数据大,保存函数后再处理会RE(原因目测是存储用数组开不了那么大)
1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 const int maxn=100000; 9 long long n; 10 int m[maxn],phi[maxn],p[maxn],pt; 11 int euler() 12 { 13 phi[1]=1; 14 int N=maxn; 15 int k; 16 for(int i=2;i<N;i++) 17 { 18 if(!m[i])//i是素数 19 p[pt++]=m[i]=i,phi[i]=i-1; 20 for(int j=0;j<pt&&(k=p[j]*i)<N;j++) 21 { 22 m[k]=p[j]; 23 if(m[i]==p[j])//为了保证以后的数不被再筛,要break 24 { 25 phi[k]=phi[i]*p[j]; 26 /*这里的phi[k]与phi[i]后面的∏(p[i]-1)/p[i]都一样(m[i]==p[j])只差一个p[j],就可以保证∏(p[i]-1)/p[i]前面也一样了*/ 27 break; 28 } 29 else 30 phi[k]=phi[i]*(p[j]-1);//积性函数性质,f(i*k)=f(i)*f(k) 31 } 32 } 33 } 34 int main(){ 35 euler(); 36 scanf("%lld",&n); 37 long long m=sqrt(n); 38 int i,j; 39 long long ans=0; 40 for(i=1;i<=m;i++){ 41 if(n%i==0){ 42 ans+=phi[n/i]*i; 43 ans+=(n/i)*phi[i]; 44 } 45 } 46 printf("%lld\n",ans); 47 return 0; 48 }
解2:多花点时间,每次都算一遍。并不会TLE,神奇
代码是从hzw学长那学到的,精简得很。
1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 const int mxn=100000; 9 long long n,m; 10 long long phi(long long x){ 11 long long a=x; 12 for(long long i=2;i<=m;i++){ 13 if(x%i==0){//找到因数 14 a=a/i*(i-1);//基本计算公式 a*=((i-1)/i) 15 while(x%i==0)x/=i;//除去所有相同因数 16 } 17 } 18 if(x>1)a=a/x*(x-1);//处理最后一个大因数 19 return a; 20 } 21 int main(){ 22 scanf("%lld",&n); 23 m=sqrt(n); 24 int i,j; 25 long long ans=0; 26 for(i=1;i<=m;i++){ 27 if(n%i==0){ 28 ans+=phi(n/i)*i; 29 ans+=(n/i)*phi(i); 30 } 31 } 32 printf("%lld\n",ans); 33 return 0; 34 }
本文为博主原创文章,转载请注明出处。