题目链接:http://poj.org/problem?id=2480
题目大意:
给定一个数字N,求∑gcd(i, N) 1<=i <=N 的值。
题目思路:
x是一个数字,m与n互素,则gcd(x,m*n) = gcd(x, m) * gcd(x, n) 令g(y) = gcd(x, y) 那么g(y)是一个积性函数。令f(N) = ∑gcd(i, N)
满足gcd(x, n) = 1 的个数是欧拉函数φ(n),那么可以知道,满足gcd(x, n) = p 的个数可以这么求:x 和 n 同时除以 p ,那么gcd(x/p, n/p) = 1 ,那么个数就是φ(n/p)。
分解N = p1^a1 * p2^a2 * …… *pn^an ,则f(N) = f(p1^a1 * p2^a2 * …… *pn^an) = f(p1^a1) * f(p2^a2) * …… * f(pn^an);
可以枚举pi^ai的因数,对于f(pi^ai) = 1 * φ(pi^ai) + pi * φ(pi^(ai-1)) + pi^2 * φ(pi^(ai-2)) + …… + pi^(ai-1) * φ(pi) + pi^ai * φ(1);
根据φ(pi^ai) = pi^ai - pi^(ai-1),那么可以化简上面的式子:f(pi^ai) = ai * pi^ai + ai * pi^(ai-1) + pi^ai = pi^ai * (ai + ai/pi + 1);
所以,f(N) = N * (a1 + a1/p1 + 1) * (a2 + a2/p2 + 1) * …… * (an + an/pn + 1)。
这题当然不是自己想出来的,但是学习了一下积性函数,看的神牛的解题代码:http://hi.baidu.com/lydrainbowcat/item/66a0c9088f876f12acdc70ba 说来这神牛是我的学弟,比我小一届貌似,一个高中的,竟然还都是省理的,唉……惭愧
不说了,都是泪……什么也不想了,专注刷题。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cctype> 6 #include <stack> 7 #include <queue> 8 #include <map> 9 #include <set> 10 #include <vector> 11 #include <cmath> 12 #include <algorithm> 13 #define lson l, m, rt<<1 14 #define rson m+1, r, rt<<1|1 15 using namespace std; 16 typedef long long int LL; 17 const int MAXN = 0x3f3f3f3f; 18 const int MIN = -0x3f3f3f3f; 19 const double eps = 1e-9; 20 const int dir[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1}, 21 {1,1},{1,-1},{-1,-1}}; 22 LL n, i, j, ans; 23 int main(void){ 24 #ifndef ONLINE_JUDGE 25 freopen("poj2480.in", "r", stdin); 26 #endif 27 while (~scanf("%lld", &n)){ 28 ans = n; 29 for (i = 2; i * i <= n; ++i){ 30 j = 0; 31 if (n % i == 0){ 32 while (n % i == 0){ 33 j++; n /= i; 34 } 35 ans /= i; ans = ans * (i * j - j + i); 36 } 37 } 38 if (n > 1){ 39 ans /= n; ans = ans * (n - 1 + n); 40 } 41 printf("%lld\n", ans); 42 } 43 44 return 0; 45 }
开始用cin,cout超时一次,后来发现 i ,j,不应该用 int ,应该用LL,这才过了,32ms
另外一份比较快的代码:谢谢Wahaha_hnu llw学长,还没看懂,继续有时间继续研究
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 5 using namespace std; 6 7 typedef __int64 LL; 8 #define N 70000 9 10 LL n; 11 LL f[N],prime[N],primeNum; 12 LL a[N],b[N],cnt, ans; 13 bool vis[N]; 14 void sieve() 15 { 16 int i,j; 17 for(i=0;i<N;i++) f[i]=1; 18 f[0]=f[1]=0; 19 for(i=2;i*i<N;i++) 20 if(f[i]) 21 for(j=i*i;j<N;j+=i) 22 f[j]=0; 23 j=0; 24 for(i=2;i<N;i++) 25 if(f[i]) 26 prime[j++]=i; 27 primeNum=j; 28 } 29 void dfs(int k,LL x) 30 { 31 int i,j; 32 LL y,t; 33 if(k==cnt) 34 { 35 y=n/x; 36 for(i=0;i<cnt;i++) 37 if(!vis[i]) 38 y-=y/a[i]; 39 ans+=x*y; 40 // printf("x=%I64d y=%I64d\n",x,y); 41 return ; 42 } 43 t=1; 44 for(i=0;i<b[k];i++) 45 { 46 dfs(k+1, x*t); 47 t*=a[k]; 48 } 49 vis[k]=1; 50 dfs(k+1, x*t); 51 vis[k]=0; 52 } 53 int main() 54 { 55 int i,j,k; 56 57 sieve(); 58 while(scanf("%I64d",&n)==1) 59 { 60 LL x=n; 61 cnt=0; 62 for(i=0;i<primeNum &&prime[i]*prime[i]<=x;i++) 63 if(x%prime[i]==0) 64 { 65 a[cnt]=prime[i], b[cnt]=0; 66 while(x%prime[i]==0) 67 b[cnt]++, x/=prime[i]; 68 cnt++; 69 } 70 if(x>1) a[cnt]=x, b[cnt]=1, cnt++; 71 // printf("cnt=%I64d\n",cnt); 72 // for(i=0;i<cnt;i++) 73 // printf("%I64d %I64d\n",a[i], b[i]); 74 75 ans=0; 76 memset(vis,0,sizeof(vis)); 77 dfs(0,1); 78 printf("%I64d\n",ans); 79 } 80 return 0; 81 }
这份代码可以16ms过的……