欧拉函数在OI中是个非常重要的东西,不知道的话会吃大亏的.
欧拉函数用希腊字母φ表示,φ(N)表示N的欧拉函数.
对φ(N)的值,我们可以通俗地理解为小于N且与N互质的数的个数.
欧拉函数的一些性质:
1.欧拉函数是积性函数,但不是完全积性函数,即φ(mn)=φ(n)*φ(m)只在(n,m)=1时成立.
2.对于一个正整数N的素数幂分解N=P1^q1*P2^q2*...*Pn^qn.
φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pn).
3.除了N=2,φ(N)都是偶数.
4.设N为正整数,∑φ(d)=N (d|N).
根据性质2,我们可以在O(sqrt(n))的时间内求出一个数的欧拉函数值.
code:(代码来自POJ2407,一道裸的欧拉函数应用)
var n:longint; function phi(num:longint):longint; var o,x:longint; ret:extended; begin x:=num; ret:=x; for o:=2 to trunc(sqrt(num)) do if x mod o=0 then begin ret:=ret*(1-1/o); while x mod o=0 do x:=x div o; end; if x>1 then ret:=ret*(1-1/x); phi:=round(ret); end; begin while not seekeof do begin readln(n); if n=0 then break; writeln(phi(n)); end; end.
如果我们要求1000000以内所有数的欧拉函数,怎么办.
上面的方法复杂度将高达O(N*sqrt(N)).
我们来看看线性筛法的程序:
const MAX=1000000; var Prime:array[0..MAX] of longint; v:array[0..MAX] of boolean; procedure GetPrime; var i,j,tmp,size:longint; begin size:=0; fillchar(v,sizeof(v),0); for i:=2 to MAX do begin if not v[i] then begin inc(size); prime[size]:=i; end; j:=1; while (j<=size)and(prime[j]*i<MAX) do begin v[i*prime[j]]:=true; if i mod prime[j]=0 then break; inc(j); end; end; end; begin GetPrime; end.
它在O(N)的时间内遍历了所有的数,并且有很多的附加信息,
那么我们是不是能在筛素数的同时求出所有数的欧拉函数呢.
答案是可以.
1.对于筛出来的素数,φ(P)=P-1.
在while循环内
2.若i mod prime[j]=0,那么φ(i*prime[j])=φ(i)*prime[j]
3.若i mod prime[j]≠0,那么φ(i*prime[j])=φ(i)*(prime[j]-1)
2,3请读者自己证明,其中3用到了欧拉函数的积性.
code:
const MAX=1000000; var Phi,Prime:array[0..MAX] of longint; v:array[0..MAX] of boolean; procedure GetPrime; var i,j,tmp,size:longint; begin size:=0; fillchar(v,sizeof(v),0); for i:=2 to MAX do begin if not v[i] then begin inc(size); prime[size]:=i; phi[i]:=i-1; end; j:=1; while (j<=size)and(prime[j]*i<MAX) do begin tmp:=i*prime[j]; v[tmp]:=true; if i mod prime[j]=0 then begin phi[tmp]:=phi[i]*prime[j]; break; end else phi[tmp]:=phi[i]*(prime[j]-1); inc(j); end; end; end; begin GetPrime; end.