POJ Longge's problem 2480
Longge's problem
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 5880 | Accepted: 1862 |
Description
Longge is good at mathematics and he likes to think about hard mathematical problems which will be solved by some graceful algorithms. Now a problem comes: Given an integer N(1 < N < 2^31),you are to calculate ∑gcd(i, N) 1<=i <=N.
"Oh, I know, I know!" Longge shouts! But do you know? Please solve it.
"Oh, I know, I know!" Longge shouts! But do you know? Please solve it.
Input
Input contain several test case.
A number N per line.
A number N per line.
Output
For each N, output ,∑gcd(i, N) 1<=i <=N, a line
Sample Input
2 6
Sample Output
3 15
Source
POJ Contest,Author:Mathematica@ZSU
首先吐槽下、看到我下面注释掉的内容没 、坑爹呀
说好的 N<2^31呢
给你的 N 64位的,元芳、你怎么看、、、、、、
好了,吐槽完毕!
说下这题的解法
gcd(n,i)=d
gcd(n/d,i/d)=1
求出 所有最大公约数为d的个数 即 phi【n/d】 phi【】是欧拉函数
那么最大公约数为 d 的总和就是 d*phi[n/d]
phi[n/d]=n/d(1-1/p1)*(1-1/p2)*(1-1/pk)
p1 p2 ... pk 是 n/d 的素因子
d*phi[n/d]=d*n/d(1-1/p1)(1-1/p2)...(1-1/pk)
n(1-1/p1)*(1-1/p2)..(1-1/pk)
这样的话对于每个d 的总和和 就有相应的 n(1-1/p1)*(1-1/p2)..(1-1/pk)
根据排列组合 最后和为 n*(1+r1*(1-1/p1))*(1+r2*(1-1/p2))。(1+rn*(1-1/pn))
rn为pn N用素因子表示 的次方数
#include <iostream> #include <map> #include <stdio.h> #include <math.h> #include <string.h> #include <stdlib.h> #include <algorithm> using namespace std; /*#define N 100000 bool h[N]; int pm[40000]; void GetPrime() { __int64 i,j,cnt=1; pm[0]=2; for(i=2;i<N;i+=2) h[i]=1; for(i=3;i<N;i+=2) if(!h[i]) { pm[cnt++]=i; for(j=i*i;j<N;j+=i) h[j]=1; } } int cnt; int rc[22][2]; void del(__int64 n) { cnt=0; int i; int m=sqrt(n*1.0); for(i=0;pm[i]<=m;i++) if(n%pm[i]==0) { rc[cnt][0]=pm[i]; rc[cnt][1]=0; while(n%pm[i]==0){rc[cnt][1]++;n/=pm[i];} cnt++; if(n==1) break; } if(n>1) { rc[cnt][0]=n;rc[cnt++][1]=1;} }*/ int main() { __int64 n; // GetPrime(); __int64 sum=0; while(scanf("%I64d",&n)!=EOF) { // del(n); sum=n; __int64 t=n; int cnt=0; if(t%2==0) { while(t%2==0) {t/=2;cnt++;} sum=sum/2*(2+2*cnt-cnt); } for(__int64 i=3;i*i<=n;i+=2) { if(t%i==0) { cnt=0; while(t%i==0) {t/=i;cnt++;} sum=sum/i*(i+i*cnt-cnt); } } if(t>1) sum=sum/t*(t+t-1); printf("%I64d\n",sum); } return 0; }