The Euler function
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5379 Accepted Submission(s): 2286
3 100
3042
理解完这个算法后再看紫书p312就觉得很好懂了,太神了。。。。谁想出来的。。。下面详细地讲一遍。
首先,题中要求求a~b的欧拉函数之和,那么欧拉函数是什么呢?就是不超过该书的与它互素的数的个数,比如phi(4)=2,因为1,3都与4互素。
不超时的解法是将1~3000000的欧拉函数都算出来,读入a,b时做累加就行了。
现在的问题是如何高效地求欧拉函数
这里要知道三个性质:
1、若一个素数为p,那么phi(p)= p-1
2、若一个数为素数的k次幂,那么phi(p)= p^-(p^k)/p(就是这个数本身减去能被p整除的个数)
phi(p) = (p-1)*(p^(k-1))
3、欧拉函数是积性函数,若m,n互质,φ(mn)= φ(m)φ(n)
那么就能得一个数
n=(p1-1)(p2-1)(p3-1).....(pn-1)*(p^(k1-1))*(p^(k2-1))*(p^(k3-1))*.....(p^(kn-1))
(上下同乘以n,下方的n用p1*p2*p3....*pn表示)
=k*(p1-1)(p2-1)(p2-1)...(pn-1)/p1*p2*p3*...*pn
根据上式能得出以下计算欧拉函数的程序
int vis[maxn];
void init(){
int i,j;
memset(vis, 0, sizeof(vis));
for(i=1;i<maxn;i++){
vis[i]=i;
}
for(i=2;i<maxn;i++){
if(vis[i]==i){
for(j=i;j<maxn;j=j+i){
vis[j]=(vis[j]/i)*(i-1);
}
}
}
}
首先,将数组中从1到maxn赋值
如果vis[i]==i 的话,说明这个值没有被改变过,那么这个数是素数
既然是素数,就做循环将以这个数为质因数的数做上面推倒出来的式子的处理(某数/p*(p-1))
下为完整程序
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <cmath>
#define maxn 3000005
using namespace std;
int vis[maxn];
void init(){
int i,j;
memset(vis, 0, sizeof(vis));
for(i=1;i<maxn;i++){
vis[i]=i;
}
for(i=2;i<maxn;i++){
if(vis[i]==i){
for(j=i;j<maxn;j=j+i){
vis[j]=(vis[j]/i)*(i-1);
}
}
}
}
int main(){
long long a,b,result,i;
init();
while(cin>>a>>b){
result=0;
for(i=a;i<=b;i++){
result=result+vis[i];
}
cout<<result<<endl;
}
return 0;
}