zoukankan      html  css  js  c++  java
  • [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         
  • 相关阅读:
    20191330雷清逸 学习笔记4
    sort
    20191330雷清逸 MyOD(选作,计入平时成绩)
    20191330雷清逸 Linux C语言编程基础(必做)
    20191330雷清逸 学习笔记3
    20191330雷清逸 学习笔记2
    无限的技能
    20191330 雷清逸 学习笔记1
    2021-2022-1-diocs-Linux系统编程第四周学习笔记
    Linux下man命令的使用
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4370965.html
Copyright © 2011-2022 走看看