GCD Again

GCD Again
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2732 Accepted Submission(s): 1157

Problem Description
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
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.

Output
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.

Sample Input
2
4
0

Sample Output
0
1

分析:
欧拉函数的运用。

欧拉函数: 对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目。例如euler(8)=4,因为1,3,5,7均和8互质。
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。

欧拉函数性质: 1、 φ(mn) = φ(m) φ(n)
2、若n为奇数,φ(2n) = φ(n)。
欧拉公式的延伸:一个数的所有质因子之和是euler(n)*n/2。
本题是求小于n与n的公因子大于1的个数。即求n-euler(n)-1;(还要减去n自己)

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的一个质因子。

AC代码:

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int euler(int n)
{
    int ans = n;
    int m = sqrt(n+0.5);
    for(int i=2;i<=m;i++)
    {
        if(n%i==0)
        {
            ans=ans/i*(i-1);
            while(n%i==0)
                n/=i;
        }
    }
    if(n>1)
        ans = ans/n*(n-1);
    return ans;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF && n)
    {
        printf("%d\n",n-euler(n)-1);
    }
    return 0;
}

筛法求欧拉函数:

const int maxn = 1000005;
int phi[maxn];

void phi_table()
{
    memset(phi,0,sizeof(phi));
    phi[1] = 1;
    for(int i=2;i<=maxn;i++)
    {
        if(!phi[i])
        {
            for(int j=i;j<=maxn;j+=i)
            {
                if(!phi[j]) phi[j] = j;
                phi[j] = phi[j]/i*(i-1);
            }
        }
    }
}

代码如上,为了便于理解一下用以下代码显示出求1~16的具体变化过程。有用筛法求素数的经验可知,从2开始处理,且每次把i的倍数全部赋值,则可以保证每次处理的i都为质数。由于euler(x)=φ(x) =x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…(1-1/pn),其中p1,p2……pn为x的所有素因数。所以只需要找出所有的质数,然后判断n是否除的尽该质数即可(质数的倍数一定包含这个质因子),且保证了每个质因子只处理一次。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

const int maxn = 1000005;
int phi[maxn];

void phi_table()
{
    memset(phi,0,sizeof(phi));
    phi[1] = 1;
    for(int i=2;i<=16;i++)
    {
        if(!phi[i])
        {
            cout<<"i="<<i<<" ";
            for(int j=i;j<=16;j+=i)
            {
                if(!phi[j]) phi[j] = j;
                phi[j] = phi[j]/i*(i-1);
            }
        }
        for(int i=1;i<=16;i++)
            cout<<phi[i]<<" ";
        cout<<endl;
    }
}
int main()
{
    phi_table();
    return 0;
}

结果:
i=2 1 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8
i=3 1 1 2 2 0 2 0 4 6 5 0 4 0 7 10 8
1 1 2 2 0 2 0 4 6 5 0 4 0 7 10 8
i=5 1 1 2 2 4 2 0 4 6 4 0 4 0 7 8 8
1 1 2 2 4 2 0 4 6 4 0 4 0 7 8 8
i=7 1 1 2 2 4 2 6 4 6 4 0 4 0 6 8 8
1 1 2 2 4 2 6 4 6 4 0 4 0 6 8 8
1 1 2 2 4 2 6 4 6 4 0 4 0 6 8 8
1 1 2 2 4 2 6 4 6 4 0 4 0 6 8 8
i=11 1 1 2 2 4 2 6 4 6 4 10 4 0 6 8 8
1 1 2 2 4 2 6 4 6 4 10 4 0 6 8 8
i=13 1 1 2 2 4 2 6 4 6 4 10 4 12 6 8 8
1 1 2 2 4 2 6 4 6 4 10 4 12 6 8 8
1 1 2 2 4 2 6 4 6 4 10 4 12 6 8 8
1 1 2 2 4 2 6 4 6 4 10 4 12 6 8 8

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值