[BZOJ2190&BZOJ2705]欧拉函数应用两例

欧拉函数phi[n]是表示1~n中与n互质的数个数。

可以用公式phi[n]=n*(1-1/p1)*(1-1/p2)*(1-1/p3)...*(1-1/pk)来表示。(p为n的质因子)


 

求phi[p]的过程:

 1 procedure calc(p:longint;var sum:longint);
 2 var i:longint;
 3 begin
 4     sum:=p;
 5     for i:=2 to trunc(sqrt(p)) do
 6         if p mod i=0 then 
 7         begin
 8             sum:=sum div i*(i-1);    
 9             while p mod i=0 do p:=p div i;
10                         // 保证每次都是质因子
11         end;
12     if p<>1 then sum:=sum div p*(p-1);
13         // 如果p自身是质数的情况
14 end;

 


 

 

BZOJ2190

  直接套用即可,不处理1的情况最后加上3。需要注意的是读进来的方阵大小应该-1。

  直接贴代码。

 1 program bzoj2190;
 2 const maxn=40010;
 3 var n,i,ans:longint;
 4       phi:array[-1..maxn]of longint;
 5 procedure calc(p:longint;var sum:longint);
 6 var i:longint;
 7 begin
 8     sum:=p;
 9     for i:=2 to trunc(sqrt(p)) do
10         if p mod i=0 then 
11         begin
12             sum:=sum div i*(i-1);    
13             while p mod i=0 do p:=p div i;
14         end;
15     if p<>1 then sum:=sum div p*(p-1);
16 end;
17 
18 begin
19     readln(n);dec(n);
20     for i:=2 to n do calc(i,phi[i]);
21     ans:=0;
22     for i:=2 to n do inc(ans,phi[i]);
23     if n<>1 then writeln(ans*2+3) else writeln(0);
24 end.

BZOJ 2705

  刚开始看可能无从下手。但是再看一眼会发现,如果枚举某个数与n的最大公约数,再求出这样的数有多少的话可能就有方法处理了。

  我们来思考有多少个数与n的最大公约数是x,不难想出,当这个数/x,n/x的时候两数互质。也就是其个数=phi[n/x]!

  所以只需要枚举所有的最大公约数(枚举到sqrt(n))即可。

  需要注意的是如果n正好是完全平方数,sqrt(n)会被计算两次。于是特判。

  另外这道题给我们一点启发:sigma(phi[n/i])(n mod i=0)=n!

  虽然目前还没有发现有哪里可以应用,但是式子非常优美。。>_<

  

 1 program bzoj2705;
 2 var i:longint;
 3       ans,n:int64;
 4 
 5 function phi(p:int64):int64;
 6 var i:longint;
 7     ans:int64;
 8 begin
 9     ans:=p;
10     for i:=2 to trunc(sqrt(p)) do if p mod i=0 then
11     begin
12         ans:=ans*(i-1) div i;
13         while p mod i=0 do p:=p div i;
14     end;
15     if p<>1 then ans:=ans*(p-1) div p;
16     exit(ans);
17 end;
18  
19 begin
20     //sign(input,'a.in');reset(input);
21     while not eof do 
22     begin
23         readln(n);
24         ans:=0;
25         for i:=1 to trunc(sqrt(n)) do if n mod i=0 then 
26         begin
27             inc(ans,i*phi(n div i));
28             if i*i<>n then inc(ans,(n div i)*phi(i));
29         end;
30         writeln(ans);        
31     end;
32 end.
33         

 

posted @ 2015-03-27 10:00  mjy0724  阅读(238)  评论(0编辑  收藏  举报