这道题大一的时候做过,那时候还不知道有欧拉函数,超时了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;
}