标签:数论 poj
Longge‘s problem
Time Limit: 1000MS |
|
Memory Limit: 65536K |
Total 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
2
6
Sample Output
3
15
题目意思很简单:给一个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
POJ 2480 Longge's problem (欧拉函数+乘性函数)
标签:数论 poj
原文地址:http://blog.csdn.net/u013068502/article/details/45268369