百度百科有一道例题就是用容斥原理计算这个的,如果不明白的可以先看看那个。
我们首先要利用容斥原理求得和m不互质的数,为此我们先找出m的素因子
void get_fac(ll m) //要找的m的素因子
{
for(ll i=2;i*i<=m;i++)
{
if(m%i==0)
{
fac[cnt++]=i; //fac存素因子,cnt从0开始
while(m%i==0) //保证后面的数是m的素因子
m/=i;
}
}
if(m>1)
fac[cnt++]=m;
}
如果一个数有m的素因子,那么他就一定不和m互质,比如30的素因子有2,3,5,那么所有2的倍数就不和30互质,同理3的倍数,5的倍数也不和30互质,这里假设要求1~30内和30互质的数,那么r=30.设X1是2在1到30中2的倍数的个数,则X1=15,同理对3,X2=10,对5,X3=6,对23,X4=5 ;对2 * 5,X5=3;对3 * 5,X6=2;对23*5,X7=1,所以和30不互质的数就有X1+X2+X3-(X4+X5+X6)+X7=22个,则与30互质的数就有8个,和30的欧拉函数值相等.
程序写法:
1.dfs():在递归的每一层都决策一下这个数选不选,第几层就是第几个数.
void dfs(int pos,int use,int cur,int up)
{
if(pos==cnt) //有一条一个数都没用
{
if(use == 0)
return ;
if(use&1)
sum+=up/cur; //sum保存和m不互质的数的个数
else
sum-=up/cur;
return ;
}
dfs(pos+1,use+1,cur*fac[pos],up);
dfs(pos+1,use,cur,up);
}
//调用形式:dfs(0,0,1,r); //(递归层数,用了的数的数量,1保存每一项(即X1或X2..)的值,上限范围);
2.位运算
ll Find(ll up) //up表示上限
{
if(n==1) return up; //1和任意数互质
if(up==1) return 1; //上限是1就是只有一个数
ll res=0;
for(ll i=1;i<(1<<cnt);i++) //i的二进制表示用了哪几个数,比如i=3,二进制为011就表示用了第一个数和第二个数,i=4就表示用了第三个数
{
ll p=1,coun=0;
for(ll j=1;j<=cnt;j++)
{
if(i&(1<<(j-1)))
{
p*=fac[j];
coun++;
}
}
res+=(coun%2)?up/p:(-up/p);
}
return up-res; //res为和m不互质的数的个数,那么up-res就是互质的数的个数
}