容斥原理的应用,具体分析见下面代码注释:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,r;
//计算1--r中与n互素数的个数
//思路跟计算n的欧拉函数值一样,但这里没有公式化简
//所以采用k位2进制进行模拟(k表示n在r范围内素因子的个数)
//从1--2^k-1中的每一位数的二进制中1的分布表示刚好可以对应
//不同的因子组合情况
int solve()
{
int i,j,k=0,ans=0;
int prime[100]; //n的素因子表
for(i=2;i*i<=n;i++)//求出1--r中n所有的素因子,控制条件必须是i*i,否则会超时
if(n%i==0)
{
prime[k++]=i;
while(n%i==0)
n=n/i;
}
if(n>1) //除了最后n未除尽的情况外,i=2,3或n为素数的情况也都由此处理
prime[k++]=n;
for(i=1;i<(1<<k);i++) //i<<N表示2^N
{
j=i;
int cnt=0,mult=1; //mult用于记录每一种情况下因子的最小公倍数
int m=0; //m用于记录二进制的位数
while(j)
{
if(j&1)
{
cnt++; //记录二进制中1的个数,即因子的个数
mult=mult*prime[m];
}
j=j>>1; //j右移一位
m++;
}
int cur=r/mult; //1--r中能被mult整除数的个数
if(cnt%2) //奇数个因子情况
ans+=cur;
else
ans-=cur;
}
return r-ans;
}
int main()
{
while(cin>>r>>n)
{
int n1=n;
int ans=solve();
cout<<"1--"<<r<<"中与"<<n1<<"互素数的个数为: "<<ans<<endl;
}
return 0;
}