• NYOJ 1007


    在博客NYOJ 998 中已经写过计算欧拉函数的三种方法,这里不再赘述。

    本题也是对欧拉函数的应用的考查,不过考查了另外一个数论基本定理:如何用欧拉函数求小于n且与n互质所有的正整数的和。

      记euler(x)公式能计算小于等于x的并且和x互质的数的个数;我们再看一下如何求小于等于n的和n互质的数的和, 我们用sum(n)表示;

      定理:若gcd(x, a)=1,则有gcd(x, x-a)=1;

        证明:反证法:假设gcd(x, x-a)=k (k>1),那么有(x-a)%k=0---1式,x%k=0---2式; 由1式和2式可得 a%k=0---3式; 由2式和3式可得gcd(x, a)=k,与gcd(x,a)=1矛盾,假设不成立,即原式得证;

        由此我们可以得知小于x并且与x互质的数必然是成对出现的并且有对应的一对数和为x;所以有sum(n)=euler(n)/2*n;

    故本题的写法为:

    
    
    
     1 #include <iostream>
     2 #include <cstdio>
     3 using namespace std;
     4 
     5 const int N=1000000007 ;
     6 typedef long long LL;
     7 
     8 LL Euler(LL n){
     9     LL ans = n;
    10     for(int i = 2; i * i <= n; i++){
    11         if(n % i == 0){
    12             ans = ans / i * (i-1);
    13             while(n % i == 0)
    14                 n /= i;
    15         }
    16     }
    17     if(n > 1) ans = ans / n * (n-1);
    18     return ans;
    19 }
    20 
    21 //计算得到小于n且与n互质的正整数的和   
    22 long long Euler_sum(long long n){  
    23     if(n==1)  
    24         return 1;  
    25     else  
    26         return n*Euler(n)/2;  
    27 }  
    28 
    29 int main(){     
    30     int t;
    31     cin>>t;
    32     while(t--){ 
    33         LL n,m;
    34         cin>>n>>m;
    35         LL ans = 0;
    36         for(int i = 1; i * i <= n; i++){
    37             if(n % i == 0){
    38                 if(i >= m){
    39                     int d = i;
    40                     ans = (ans+d*Euler_sum(n/d) ) %N;   
    41                        //考虑gcd(x,n)   1<=x<=n
    42                     //其中gcd(x/d,n/d) = 1 ,Euler(n/d)我们得到的是能够使得gcd(x,n) = d 的x的取值的个数
    43                     //Euler_sum(n/d)我们得到的是小于n/d且与n/d互质的正整数的和
    44                     //暂且设“小于n/d且与n/d互质的正整数”分别为a1,a2...an等那么乘以d之后得到的数列b1 = a1*d  b2 = a2*d ...bn = an*d
    45                     //那么b1 b2 ...bn等数与n的公约数就是d ,而d>=m,满足题设    
    46                     //所以在公约数为d的情况下这些能够满足gcd(x,n) = d >=m的数的和,即b1+b2+...bn = (a1+a2+...+an)*d,
    47                     //而(a1+a2+...+an) = Euler_sum(n/d) 故b1+b2+...bn = d*Euler_sum(n/d)
    48                     //这样就处理完了公约数为d的情况,同理按照for循环,1~sqrt(n)遍历,
    49                     //分别测试公约数为别等于i(i从1到sqrt(n)遍历)是否满足n%i==0即可,若满足就令d=i,ans+=d*Euler_sum(n/d)  
    50                 }
    51                 if(i * i != n && n / i >= m){
    52                     int d = n / i;
    53                     ans = (ans+ d*Euler_sum(n/d) )%N;  
    54                     //在上部for循环中进行到sqrt(n),这一步就是处理后面的东西:n/i   
    55                 }  
    56             }
    57         }
    58         cout<<ans<<endl;
    59     }
    60     return 0;
    61 }
  • 相关阅读:
    dotnetcore3.1 WPF 实现多语言
    dotnetcore3.1 WPF 中使用依赖注入
    [svc]打通mysql主从同步
    [svc]glusterfs的简单部署
    [svc]inotify+rsync解决nfs单点问题
    [svc]rsync简单部署
    [svc]linux文件权限
    [svc]ssh批量分发key/批量用户管理
    [svc]NFS存储企业场景及nfs最佳实战探究
    [svc]mount命令及解决因/etc/fstab错误导致系统不能启动故障
  • 原文地址:https://www.cnblogs.com/liugl7/p/6260165.html
Copyright © 2020-2023  润新知