• 找新朋友


    来源

    http://139.196.145.92/contest_show.php?cid=1890#problem/C

    Description
    新年快到了,“猪头帮协会”准备搞一个聚会,已经知道现有会员N人,把会员从1到N编号,其中会长的号码是N号,凡是和会长是老朋友的,那么该会员的号码肯定和N有大于1的公约数,否则都是新朋友,现在会长想知道究竟有几个新朋友?请你编程序帮会长计算出来。
    
    Input
    输入:第一行是测试数据的组数CN(Case number,1<cn<10000),接着有CN行正整数N(1<n<32768),表示会员人数。
    
    Output
    输出:对于每一个N,输出一行新朋友的人数,这样共有CN行输出。
    
    Sample Input
    2
    25608
    24027
    
    Sample Output
    7680
    16016
    
    前置知识:
    1. Elur函数

      对于正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目.如:(varphi (8)=4),为1,3,5,7

      性质:

      • 若p为质数,显然(varphi(p)=p-1)
      • (p=a^b(a,b,p in N^*))(a为质数),(varphi(p)=a^b-a^{(b-1)}=(a-1)*a^{(b-1)}),因为一共有(n=a^b)个数,想要获得所有与n互质的数,只需要除去a的倍数即可.这里简单地解释一下(a^{(b-1)}):设有n中有m个a的倍数,则有(ma=a^b => m=a^{(b-1)}).
      • Elur函数是积性函数,即:(varphi(mn)=varphi(m)*varphi(n)(m,n互质))

      (p=a_1^{b_1}*a_2^{b_2}*a_3^{b_3}...(a_i为质数{p,a_i,b_i|p,a_i,b_i in N^*})),由算术基本定理可知,这里的p可以表示所有的正整数.那么,根据以上三条性质可得:

      [varphi(p)=(a_1-1)*(a_2-1)*(a_3-1)...a_1^{(b_1-1)}*a_2^{(b_2-1)}*a_3^{(b_3-1)}... ]

    分析问题:
    1. 显然只要套一下公式即可
    代码:
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    ll getNum(ll n);
    
    int main()
    {
        ll n,num,ans;
        scanf("%lld",&num);
        while(num--){
            scanf("%lld",&n);
            ans = getNum(n);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
    ll getNum(ll n) //计算n中的
    {
        ll num=1;
        for(int i=2;i*i<=n;i++){  //相等的时候也需要包含在内,否则出来的时候只加一次
            if(n%i==0){  //这个内外的乘法参考了晚上的代码,很巧妙,没有对于a^(i-1)次做额外的判断
                n/=i;
                num*=(i-1);  //这里乘了a
                while(n%i==0){  //设n=i^a+j,这边乘了a-1次
                    n/=i;
                    num*=i;
                }
            }
        }
        if(n>1){
            num*=n-1;
        }
        return num;
    }
    

    注:

    • 这边的质数i的遍历是从2开始依次向上遍历的,但合数,如:4不会影响到结果,因为n已经被质数2筛过了
    • wa了两发,都是因为i*i<n,因为如果没有包括i*i=n的范围,那么最后的num*=n-1,有时应该是num*=(n-1)*n
  • 相关阅读:
    用C++实现网络编程---抓取网络数据包的实现方法
    UNICODE字符串与多字节字符串的转换
    MFC ComboBox的使用
    Windows API学习---线程与内核对象的同步
    Windows API学习---用户方式中的线程同步
    MFC读取XML文件并解析
    Windows API学习---插入DLL和挂接API
    常用[js,css,jquery,html]
    JDBC链接MySQL和Oracle
    使用.NET MVC框架项目开发流程(项目开发流程)
  • 原文地址:https://www.cnblogs.com/Arno-vc/p/13722545.html
Copyright © 2020-2023  润新知