题目表述:
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;
}