容斥原理模板(二进制表示)

强烈推荐手动模拟程序

#include <bits/stdc++.h>

using namespace std;

int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
int lcm(int a,int b)
{
return a*b/gcd(a,b);
}
int solve()//求1~n与n互质的数的个数
{
int prime[10]= {2,3,5};
int n=30,ans,num;
ans=0,num=3;//num是素数因子或者因子的个数,这里是素数因子
for(int i=1; i< (1<<num) ; i++)//循环次数,也就是集合个数,也就是有2^num-1个集合
{
//i就是表示第i个集合
//2^n可以用1<<n为运算表示
int mult=1,cnt=0;
for(int j=0; j<num; j++) //循环prime中的每个元素
{
if(i & (1<<j))//要掌握&运算,与i的二进制的第j位比较,看是否为1,是则选中
{
cnt++;//记录集合中元素的个数
mult = lcm(mult,prime[j]);//是否要lcm看情况
}
}
if(cnt&1)//集合元素个数为奇数就加,否则减
ans += n/mult;
else
ans -= n/mult;
}
return n-ans;
}
int main()
{
cout<<solve();
return 0;
}
可以用欧拉函数验证上述代码

#include <iostream>
#include <cmath>

using namespace std;

int Euler(int n)
{
int num=n;
for(int i=2;i<=sqrt(n);i++)
if(n%i==0)
{
num=num/i*(i-1);//先进行除法防止溢出(num=num*(1-1/p(i)))
while(n%i==0)
n/=i;
}
if(n>1)
num=num/n*(n-1);
return num;
}
int main()
{
cout << Euler(30)<< endl;
return 0;
}
 
---------------------

posted @ 2019-07-15 04:48  李艳艳665  阅读(188)  评论(0编辑  收藏  举报