您的位置:首页 > 其它

欧拉函数 因子分解 TOJ 2918 LCM Revisited---

2015-03-11 15:33 197 查看

题意

给出一个整数N (0<N<231) , 然后求出在 1-N 之间的数M 满足与N 的最小公倍数 N<LCM(M,N)<M∗N , 求满足条件的m的个数。

思路

范围比较大, 直接 求的话,肯定会超时,反向来求,只需要求出不满足条件的个数,然后用N减,即可。 很显然, 有下面两类数不满足条件:

1. 与N 互质

2. 是N的因子

接下来分别求出这两类即可。

与N互质

求比N小的与N互质的个数,可以想到用 欧拉函数。

在数论,对正整数n,欧拉函数 φ(n)是少于或等于n的数中与n互质的数的数目。

φ(n)=n∗p1−1p1∗p2−1p2∗…∗pn−1pn, 其中 pi 是N 的质因子。这里包含 1

一般求解欧拉函数的代码:

int eular(int n)
{
int eul=n;
for(int i=2; i*i<=n; i++)//数字比较大,i*i 超范围,可以long long
{
if(n%i==0)
{
eul=eul/i*(i-1); //计算欧拉函数,这里i 就是质因子了
while(n%i==0)n/=i;
}
}
if(n>1) eul=elu/n*(n-1);
return eul;
}


求N的因子的个数

求因子个数可以用下面的公式:

设 N=pa11∗pa22∗…∗pann, 则N的因子个数:

f(N)=(a1+1)∗(a2+1)∗…∗(an+1)

其中pi 是 N 的质因子。

ok,到这里两部分都已经解决了, 不过如果两个都分开求,很不幸的–TLE,

通过观察可以知道, 在用欧拉函数求互质个数,以及求N 的因子个数的时候,我们都用到了 N 的质因子。 因此我们可以考虑,提前将N

的质因子打表保存,供两个调用。而N 的上限是 231 , 最大的质因子不会超过 N−−√ 即:65536,这个复杂度还可以接受。

另外: 再求N 的质因子个的时候,还需要求出每个质因子的次数。详见代码:

代码

/*Accepted  2918    C++ 0.8K    0'00.04"    */

#include <stdio.h>

//pr标记素数, p存贮质因子,num存储质因子次数。
int pr[65540],p[300],num[300],k,n;

void prim()//将65536以内的素数,打表存储
{
pr[0]=pr[1]=pr[2]=0;
for(int i=2;i<=65536;i++)
if(pr[i]==0)
{
for(int j=i+i;j<=65536;j+=i)
pr[j]=1;
}
}
void factor(int n)
{
k=0;
for(long long i=2;i*i<=n;i++)// 这里必须是longlong 否则i*i 超int
{
if(!pr[i]&&n%i==0)
{//质因子
num[k]=0;
while(n%i==0)
num[k]++,n/=i;
p[k++]=i;//存储质因子
}
}
if(n>1)
{
p[k]=n;
num[k++]=1;
}
}
int res()
{
int res=n,sum=1;
for(int i=0;i<k;i++){
res=res/p[i]*(p[i]-1);// 欧拉函数
sum*=(num[i]+1); // 求因子个数
}
return res+sum;
}

int main()
{
prim();
while(scanf("%d",&n)&&n)
{
factor(n);
printf("%d\n",n-res()+1);// 因为两个重复包含了1, 因此需要+1
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息