poj 2480 Longge's problem [ 欧拉函数 ]

时间:2023-03-08 20:41:19

传送门

Longge's problem
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 7327   Accepted: 2416

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
题解:转自 http://li3311930.blog.163.com/blog/static/7906448820098289054587/

题意:

这题的题意很清楚啦,http://acm.pku.edu.cn/JudgeOnline/problem?id=2480,就是给出一个数n,然后求出1~n所有的数与n的最大公约数之和。

算法:

这道题我认为是很好的一道数学题,首先我们必须了解到欧拉函数,然后再通过欧拉函数去求解。

先给出一个证明吧:首先假设n有一个约数d,那么怎样计算出1~n中最大公约数为d的个数呢?很显然,这个个数实质上是等于fin(n/d)(其中先用fin代表欧拉函数),想到这里的话,基本上就确定了策略,我们先枚举出n的所有约数,然后求出每一个的欧拉函数,然后d*fin(n/d)相加后的结果即为所求,但是枚举出n的所有约数,这是一个很难的问题,首先那些因数怎么求呢?不过,题目是求和,并不是一个一个地求,于是我们把欧拉函数的公式套上,可得d*n/d*(1-1/p1)*(1-1/p2)*...*(1-1/pm),化简得到n*(1-1/p1)(1-1/p2)*..(1-1/pm),那么所有的项其实都可以提一个n出来,于是关键是求最后一部分的和,首先最后一部分其实是n/d的因数分解所得出的p1,p2,...pm,那么我们考虑假设n的因数分解是p1^r1*p2^r2*...*pn^rn,那么n的因子d其实都可以表示成p1^k1*p2^k2*...pn^kn,其中0<=ki<=ri,那么如果ki不为ri的话,n/d这个数中必然含有p1这个素因子,否则的话就不含p1这个素因子,到了这里,利用排列组合的知识我们可以写出一个最后一部分的和的公式了:(1+r1*(1-1/p1))*(1+r2*(1-1/p2))*...(1+rn*(1-1/pn));其实是这样的,当不包含p1这个素因子时,第一项选1,然后若包含p1这项因子时,那么n/d中的p1的指数可以有r1中情况,所以第一项选最后一个r1*(1-1/p1)。然后得出了最后的公式n*((1+r1*(1-1/p1))*(1+r2*(1-1/p2))*...(1+rn*(1-1/pn)));现在只需要进行因数分解,这个问题可以在大概的O(sqrt(n))的时间求出。

欧拉函数

数论,对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为Euler's totient function、φ函数、欧拉商数等。 例如φ(8)=4,因为1,3,5,7均和8互质。 从欧拉函数引伸出来在环论方面的事实和拉格朗日定理构成了欧拉定理的证明。

φ函数的值  通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数。φ(1)=1(唯一和1互质的数(小于等于1)就是1本身)。 (注意:每种质因数只一个。比如12=2*2*3那么φ(12)=12*(1-1/2)*(1-1/3)=4

13961147 njczy2010 2480 Accepted 388K 32MS G++ 1104B 2015-03-14 13:14:11
 #include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#include <string> #define ll long long
int const N = ;
int const M = ;
int const inf = ;
ll const mod = ; using namespace std; ll n,m;
ll a[N];
ll num[N];
ll tot;
ll ans; void ini()
{
m=n;
tot=;
ans=;
ll i;
for(i=;i*i<=n;i++){
if(n%i==){
a[tot]=i;
num[tot]=;
while(n%i==){
num[tot]++;
n/=i;
}
tot++;
}
}
if(n!=){
a[tot]=n;
num[tot]=;
tot++;
}
} void solve()
{
ll i;
ans=m;
for(i=;i<tot;i++){
ans=ans/a[i]*(num[i]*a[i]-num[i]+a[i]);
}
} void out()
{
printf("%I64d\n",ans);
} int main()
{
//freopen("data.in","r",stdin);
//scanf("%d",&T);
//for(cnt=1;cnt<=T;cnt++)
while(scanf("%I64d",&n)!=EOF)
{
ini();
solve();
out();
}
}