找新朋友(hdu1286,欧拉函数)

这道题大一的时候做过,那时候还不知道有欧拉函数,超时了n多次,最后借鉴了筛素法才过掉

这道题是欧拉函数的基本题


Problem 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.定义:对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目

2.欧拉函数用φ函数表示。通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数。

   比如φ(1)=1,φ(12)=12*(1-1/2)*(1-1/3)=4(12=2*2*3,12与1,5,7,11互质)


想法:

题意说的很清楚,求1~n中与n互质的数的数目

首先将n的质因子求出,然后运用欧拉函数即可


那么如何求质因子呢?

可以看我转载的另一篇文章(“求一个数的质因数(1个或n个)”),用的是其中的第一种类型。

其中的第二种类型将会在hdu2824中用到


c代码:

#include<stdio.h>
int main()
{
    //freopen("in.txt","r",stdin);
    //欧拉函数
    int i,n,m,t,gs;
    int p[1005];
    scanf("%d",&t);

    while(t--)       
    {
        scanf("%d",&n);
        m=n;
        gs=0;

        for(i=2;i*i<=n;i++)     //使用“求一个数的质因数(1个或n个)”第一种类型
        {
            if(n%i==0)
            {
                p[gs++]=i;
                while(n%i==0)
                {
                    n/=i;
                }
            }
        }
        if(n>1)
        {
            p[gs++]=n;
        }

        n=m;
        for(i=0;i<gs;i++)      //使用欧拉函数求互质数的个数
        {
            n*=(p[i]-1);
            n/=p[i];
        }
        printf("%d\n",n);
    }
    return 0;
}


这里一并附上大一时的代码,借鉴了筛素法


#include<stdio.h>
#include<string.h>
int main()
{
    //freopen("in.txt","r",stdin);
    //在此借鉴了筛素法的思想
    int t,n,i,j,s;
    int p[32770];                     //p数组用于标记是否与t互质;互质为0,否则为1
    scanf("%d",&n);

    while(n--)
    {
        memset(p,0,sizeof(p));        //初始化p数组
        scanf("%d",&t);

        for(i=2;i<t;i++)
        {
            if(t%i==0&&p[i]==0)       //如果i是t的约数,且i未被标记过 → 即i与t没有除1和i以外的公约数了
            {
                 for(j=1;i*j<t;j++)   //将i的倍数均标记为1
                    p[i*j]=1;             
            }
        }

        for(s=1,i=2;i<t;i++)          //统计0的个数,即可知道互质的个数
        {
            if(p[i]==0)
                s++;
        }
        printf("%d\n",s);
    }
    return 0;
}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值