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.
 
   

Input

 
   
Input contain several test case.
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;

}
 
   

 




你可能感兴趣的:(long)