目录见右上
站内文章欢迎各位转载,但是请注明出处(毕竟码字很辛苦哈)。

主题

欧拉函数

欧拉函数phi(i)表示1到i-1中与i互质的数的个数。

(相关内容见https://baike.baidu.com/link?url=27d62RHi2wEZfpOlihHpoF5V_tEmfgRJHKVJjAnpYIwRwZN21G_lnHpJ-dq2jfanBnBU98FloknUycYNElcM-K


  • 线性筛求欧拉函数

筛法显然是适用于一些很大范围内的求解。

详情转链接

接下来,我们就可以利用欧拉函数解决一些有趣的问题了。一般要用到欧拉函数的地方都是大范围使用,所以这不失为一种好的方法。


  • 通式求欧拉函数

这个就是利用了欧拉函数的通式来求解。

phi(x)=x*(1-1/p1)*(1-1/p2)*……*(1-1/pi)

pi为x的质因数(每一个质因数只会乘一遍)。

所以我们就先质因数分解,之后再计算就可以了。

如果需要大数取模,就可能需要再写一个逆元。


代码如下:

type

inf=record

      x:int64;

      next:longint;

     end;


var

x,w:int64;

top:longint;

Hash:array[0..100047] of longint;

Fin:array[1..100000] of inf;//储存因子


//一下一大串都是pollard_rho质因数分解的过程,最后求欧拉函数的在phi函数中

function multiply(a,b,p:int64):int64;

begin

  multiply:=0;

  while b<>0 do

  begin

   if b and 1<>0 then multiply:=(multiply+a) mod p;

   a:=a shl 1 mod p;

   b:=b shr 1;

  end;

end;

function power(a,b,p:int64):int64;

var

  s,w:int64;

begin

  s:=1;

  w:=a;

  while b<>0 do

  begin

   if b and 1<>0 then s:=multiply(s,w,p);

   w:=multiply(w,w,p);

   b:=b shr 1;

  end;

  exit(s);

end;

function Miller(x:int64):boolean;

var

  vi,vk:longint;

  vj,vl,u,t:int64;

begin

  if x=1 then exit(false);

  if x=2 then exit(true);

  u:=x-1;

  t:=0;

  while u and 1=0 do

  begin

   u:=u shr 1;

   inc(t);

  end;

  for vi:=1 to 8 do

  begin

   vj:=2+random(x-2);

   vj:=power(vj,u,x);

   for vk:=1 to t do

   begin

    vl:=multiply(vj,vj,x);

    if vl=1 then

     if (vj<>1) and (vj<>x-1) then exit(false);

    vj:=vl;

   end;

   if vj<>1 then exit(false);

  end;

  exit(true);

end;

function H(x:int64):longint;

begin

  exit((x shl 1) mod 100047);

end;

procedure ins(x:int64);

var

  v,u:longint;

begin

  v:=H(x);

  u:=Hash[v];

  while u<>0 do

  begin

   if Fin[u].x=x then exit;

   u:=Fin[u].next;

  end;

  inc(top);

  Fin[top].x:=x;

  Fin[top].next:=Hash[v];

  Hash[v]:=top;

end;

function gcd(a,b:int64):int64;

var

  c:int64;

begin

  c:=a mod b;

  while c<>0 do

  begin

   a:=b;

   b:=c;

   c:=a mod b;

  end;

  exit(b);

end;

function pollard(n,c:int64):int64;

var

  x,y,d,s,t:int64;

begin

  s:=1;

  t:=2;

  x:=1+random(n-2);

  y:=x;

  while true do

  begin

   x:=(multiply(x,x,n)+c) mod n;

   d:=gcd(abs(x-y),n);

   if (d<>1) and (d<>n) then exit(d);

   if x=y then exit(n);

   inc(s);

   if s=t then

   begin

    t:=t shl 1;

    y:=x;

   end;

  end;

end;

procedure decompose(x:int64);

var

  y:int64;

begin

  if Miller(x) then

  begin

   ins(x);

   exit;

  end;

  y:=x;

  while y>=x do

   y:=pollard(x,2+random(x-2));

  decompose(y);

  decompose(x div y);

end;


function phi(x:int64):int64;//计算欧拉函数

var

  vi:longint;

begin

  for vi:=1 to top do

   x:=x div Fin[vi].x*(Fin[vi].x-1);

  exit(x);

end;


begin

read(x);//读入

randomize;

decompose(x);//质因数分解

w:=phi(x);//计算欧拉函数

writeln(w);//输出

end.


然而pollard_rho让我写的很悲哀——真正的重点phi才那么一点点……

评论
©主题 —— Powered by LOFTER