您的位置:首页 > 其它

POJ 2480 Longge's problem 解题报告(欧拉函数 + 积性函数)

2014-04-27 08:58 393 查看
Longge's problem

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 6914 Accepted: 2234
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
    解题报告: 求∑gcd(i, N) 1<=i <=N。最简单的做法就是枚举因数,每个因数t用到的次数为 epi( n/t ), epi为欧拉函数。
    这样是可以A的,代码如下:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;

int epi(int n)
{
int ret=n;
for(int i=2; i*i<=n; i++) if(n%i==0)
{
ret=ret/i*(i-1);
while(n%i==0) n/=i;
}
if(n>1) ret=ret/n*(n-1);

return ret;
}

LL num[7000];

int main()
{
int n;
while(~scanf("%d", &n))
{
int t=0;
LL i;
for(i=1; i*i<=n; i++) if(n%i==0)
num[t++]=i, num[t++]=n/i;
if(t>=2 && num[t-1]==num[t-2]) t--;

if(t==2)
{
printf("%lld\n", (long long)n*2-1);
continue;
}

LL ans=0;
for(i=0; i<t; i++)
ans=ans+num[i]*epi(n/num[i]);
printf("%lld\n", ans);
}
}


    但是有更好更通用的做法。

    首先我们要证明在函数F(N) = ∑gcd(i, N)中,如果M,N互质,那么F(M*N)=F(M)*F(N).

    如何证明呢?我看到的一个完整的证明过程:http://hi.baidu.com/bfcdygoporbjuxr/item/f119741c5fcd9c48e75e06e0

    简单来说,就是这样:

    F(M*N)=∑gcd(i, M*N)=∑∑gcd(i*M+j*N, M*N)=∑∑gcd(i,
N)*gcd(j, M)=∑gcd(i, N)*∑gcd(j, M)=F(M)*F(N)

    证明了这个过程之后,我们可以对n进行因式分解,分解成n=p1^e1 * p2^e1 * p3^e3 ... * pn^en的形式,那么pi之间两两互质,得到F(n)=F(p1^e1)*F(p2^e2)...*F(pn^en)。

    接下来求F(p^e)=即可。F(N) = ∑gcd(i, p^e)。p^e的约数有p^0,
p^1, p^2, ..., p^e,枚举因数,整理公式,可得:

    F(p^e) = e*p^(e-1)*(p-1)+p^e。

    至此,可以求出F(n)了。代码如下:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;

int pp[40];
int ee[40];
int tol;

void decomposition(int n)
{
tol=0;
int m=sqrt(n)+0.5;

for(int i=2;i<=m;i++) if(n%i==0)
{
int t=0;
while(n%i==0) n/=i, t++;
pp[tol]=i, ee[tol]=t, tol++;
}
if(n>1) pp[tol]=n, ee[tol]=1, tol++;
}

int power(int a, int b)
{
int res=1;
while(b)
{
if(b&1)
res=res*a;
a=a*a;
b>>=1;
}
return res;
}

int main()
{
int n;
while(~scanf("%d", &n))
{
decomposition(n);

LL ans=1;
for(int i=0;i<tol;i++)
{
int p=pp[i], e=ee[i];
ans=ans*power(p, e-1)*((LL)e*(p-1)+p);
}
printf("%lld\n", ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息