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;
}





原文地址:https://www.cnblogs.com/372465774y/p/2734086.html