欧拉函数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