POJ 2480 Longge's problem (欧拉函数+乘性函数)

来源:互联网 发布:棉花期货天狼星软件 编辑:程序博客网 时间:2024/04/30 04:01
Longge's problem
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 7343 Accepted: 2422

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

26

Sample Output

315

题目意思很简单:给一个n,求所有的gcd(i,n)之和,其中1<= i <= n.
重要的是数论知识和数学分析。

大家莫急,请保证下面的知识都会了,才能解这道题。
知识:
① 乘性函数:如果对于任意的正整数n和m,且n和m互素,函数f()有f(n*m)=f(n)*f(m)。
② 如果一个函数f是乘性函数,那么它的和函数F(n)=f(d1)+f(d2)+....+f(dk)也是乘性函数,其中 di | n (即n%di==0)
③ 如果n和m互素,gcd(i,n*m)=gcd(i,n)*gcd(i,m),所有gcd()函数乘性函数。
④ 设phi()是欧拉函数,即phi(n)表示小于n的正整数中与n素数的个数,欧拉函数phi()也是乘性函数。
⑤ 关于欧拉函数有定理:设p是素数,a是一个正整数,则 phi(p^a)=p^a - p^(a-1)。

分析本题:由③知,gcd()是乘性函数,那么本题给的形式是gcd()和的形式,所以由②得本题的函数是个乘性函数,那么我们就可以按乘性函数解了。
本题暴力肯定不行,我们就找捷径,请仔细看下面分析,注意到gcd(i,n)都是n的约数,而n的约数个数不多,我们可以按这个约数来分类:(与lrj《训练指南》P125对UVA11426题目的分析一样)
设p是n的一个约数,则会存在一些i,使得gcd(i,n)=p -->gcd(i/p , n/p) = 1,即i/p和n/p互素,那么一共有几个满足条件的i呢,phi(n/p)个!!且有几个这个的i就有几个p,所以结果就是p*phi(n/p),然后对n的所有约数pi都求出来然后求和就是本题的答案,即答案是:f(n)=sum(p*phi(n/p)) ,p为n的因子。

可还有一个问题就是因为n太大,不能预处理出所有phi(i),所以我们只能拿着f(n)=sum(p*phi(n/p)) 找别的出路。

那么现在给出一个公式:f(n)=sum(p*phi(n/p)) ,那么f(p^r)=r*(p^r - p^(r-1) ) +p^r。    (依据⑤推导而来)

推导过程附在代码后面,有兴趣的可以看看,不错的。

有了这个公式,只需将n分解成 n=(p1^a1) * (p2^a2)*....*(pk^ak),由①得:
f(n)=f(p1^a1) * f(p2^a2)*....*f(pk^ak)

做数论题重要的一般还是对数的分解处理。

#include <stdio.h>#include <string.h>__int64 quick_pow(__int64 a,__int64 b){__int64 res=1;while(b){if(b&1) res*=a;b/=2;a*=a;}return res;}int main(){__int64 i,res,cnt,n;while(scanf("%I64d",&n)!=EOF){res=1;for(i=2;i*i<=n;i++){if(n%i==0){cnt=0;do{n/=i;cnt++;}while(n%i==0);__int64 t=quick_pow(i,cnt);res*=(cnt*(t-quick_pow(i,cnt-1))+t);//直接按公式计算}}if(n>1)//别忘了这一步res*=(2*n-1);printf("%I64d\n",res);}return 0;}

公式推导过程(如果真想弄明白,就尽量用笔用纸跟着算算):
f(n)=sum(p*phi(n/p)) ,那么f(p^r)=r*(p^r - p^(r-1) ) +p^r。
要用的公式:phi(p^a)=p^a - p^(a-1)。

p^r的约数的个数一共有r+1个,即p^0, p^1, p^2,....p^r
f(p^r) = sum(x*phi(p^r/x))
      = 1*phi(p^r)      +      p^1 * phi(p^(r-1))          +      p^2 * phi(p^(r-2))  +....  +    p^r * phi(p^0)
      =p^r-p^(r-1)    +      p^1*(p^(r-1)-p^(r-2))  +  p^2*(p^(r-2)-p^(r-3))   +    p^r
      =p^r-p^(r-1)    +      p^r-p^(r-1)                     +     p^r-p^(r-1) + (一共r个)+  p^r
      =r*(p^r-p^(r-1))                                                                                         +  p^r

0 0
原创粉丝点击