欧拉函数在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.
浙公网安备 33010602011771号