hdu 1787 欧拉函数算法

来源:互联网 发布:吸毒人群数据 编辑:程序博客网 时间:2024/06/09 20:40

题目大意:

输入一个整数n,让你求出0~n之间(不包括0和n)和n的公约数大于1(即不互素)的数的个数;

基本思路:

欧拉函数求出互素的数的个数,然后总共n-1个数减去互素的个数,得到答案;

补充:
欧拉函数:
给定正整数n,根据唯一分解定理,然后就会有n的素因数分解式

n=p1^a1*p2^a2*...*pk^ak为n的素因子分解式,

令Ai={x|0<=x<n-1且pi整除x}  (pi整出x,pi整出n,所以x和pi不互素,所以下面用AI的补集来计算)

那么(欧拉函数这个符号我就不打了,好麻烦的吧,就用w代替了,补集就用前面加一个-代替,交集就用&代替了)

w(n)=|-A1&-A2&...&-AK|;

那么|A1|=n/pi,i=1,2,...,k; |Ai&Aj|=n/(pi*pj);1<=i<=j<=n; (n/pi这一个计算要想清楚,因为没有n又添了0,所以数值上相等)

然后用包含排斥原理得到答案,

w(n)=|A1&A2&...&AK|=n-(n/p1+n/p2+...+n/pk)+(....)-(...)+(-1)^kn/(p1p2...pk)=n(1-i/p1)(1-1/p2)(1-1/p3)...(1/1/pk);

推导完毕;


代码如下:

注意1的时候的特殊情况;

#include<bits/stdc++.h>


int Euler(int n)
{
    int res=n;
    int m=sqrt(n);
    for(int i=2;i<=m;i++)
    {
        if(!(n%i))
            res=res/i*(i-1);
        while(!(n%i))
            n/=i;
    }
    if(n>1) res=res/n*(n-1);//这里就算剩下也只能剩下一个素数,因为sqrt所以只能剩下一个,然后必然是个素数,因为如果不是素数,前面肯定已经约了;
    return res;
}
int main()
{
    int n;
    while(scanf("%d",&n)==1)
    {
        if(!n) break;
        int sum=n-1;
        int res=Euler(n);
        printf("%d\n",res);
        if(n!=1)
        printf("%d\n",sum-res);
        else
        printf("0\n");
    }
}

原创粉丝点击