GCD Again

题目表述:

Do you have spent some time to think and try to solve those unsolved problem after one ACM contest? 
No? Oh, you must do this when you want to become a "Big Cattle". 
Now you will find that this problem is so familiar: 
The greatest common divisor GCD (a, b) of two positive integers a and b, sometimes written (a, b), is the largest divisor common to a and b. For example, (1, 2) =1, (12, 18) =6. (a, b) can be easily found by the Euclidean algorithm. Now I am considering a little more difficult problem: 
Given an integer N, please count the number of the integers M (0<M<N) which satisfies (N,M)>1.
This is a simple version of problem “GCD” which you have done in a contest recently,so I name this problem “GCD Again”.If you cannot solve it still,please take a good think about your method of study. 
Good Luck! 

输入:

Input contains multiple test cases. Each test case contains an integers N (1<N<100000000). A test case containing 0 terminates the input and this test case is not to be processed. 

输出:

For each integers N you should output the number of integers M in one line, and with one line of output for each line in input. 

样例输入:

2
4
0

样例输出:

0
1

这个题的意思是输入一个n,求小于n并且与n的公因子大于1的数的个数,我们要求等于1的时候,然后用n减去这些等于1的个数,再减去它本身,就是我们要求的个数了。

欧拉函数:对正数n,欧拉函数是少于或等于n的数中与n互质的数的数目。例如euler(8)=4,因为1,3,5,7均和8互质。互质也就是说他们的公因子为1,就是我们要求的等于1的数的个数。

euler函数表达通式:euler(x)=φ(x) =x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…(1-1/pn),其中p1,p2……pn为x的所有素因数,x是不为0的整数。 
(注意:每种质因数只一个。比如 12 = 2*2*3 那么 euler(12)=12*(1-1/2)(1-1/3)=4,特殊情况euler(1)=1。

借用网上对这个函数的描述:

euler函数详解: 
由于euler函数表达通式:euler(x)=φ(x) =x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…(1-1/pn),其中p1,p2……pn为x的所有素因数,且相同的因子只算一遍。所以假设n=a^x*b^y*c^z,其中a,b,c为质因子。所以从2开始判断是否为n的因子(找到的第一个因子一定是质因子)。当找到一个因子后如a,就计算n(1-1/a)=n/a*(a-1).又由于每个质因子计算一次,所以将a除尽,这样剩余的值就也是多个质因子的乘积,下一个找到的因子也一定是质因子。还要注意的是:因为只考虑到了根号n的情况了,还要考虑一个大于根号n的因子的情况。所以若果已经考虑了所有的质因子,n的值一定为1,若果不为1,则说明n是大于根号n的一个质因子。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int n;
int euler(int n)
{
    int ans=n;
    int m=sqrt(n);
    for(int i=2;i<=m;i++)//从2开始找素数
    {
        if(n%i==0)
        {
            ans=ans/i*(i-1);//找到的第一个肯定是素数(例如2,3,4,5,6。2,3肯定是素数,4如果可以那2一定可以,5也是素数,6如果可以那3一定可以,所以第一个肯定是素数),然后使用欧拉函数。
            while(n%i==0)//这个地方可以看上面说的,.又由于每个质因子计算一次,所以将a除尽,这样剩余的值就也是多个质因子的乘积,下一个找到的因子也一定是质因子。我其实没有特别理解,但是举个例子,拿12来说,如果不这么做的话,下一个循环i是3,12/3就是4了,但是4不是素数,所以就不对。
                n/=i;
        }
    }
    if(n>1)//到了这个地方之后,n就是一个素数了,他的质因数只有1和他本身,如果n是大于1的,那么他本身也需要进行一次欧拉函数,因为欧拉函数是每一个质因数进行欧拉公式的乘积,具体可以看上面,然后这个n在上面的循环中并没有进行欧拉公式,所以在这个地方要给他补上。
        ans=ans/n*(n-1);
    return ans;
}
int main()
{
    while(cin>>n &&n)
    {
        cout<<n-euler(n)-1<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhangjinlei321/article/details/81429824
gcd