I and OI
Past...

欧拉函数在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.
posted on 2011-08-09 11:04  exponent  阅读(7631)  评论(0编辑  收藏  举报