容斥的几种写法
容斥公式本身就是 枚举出状态的组合,算其乘积,奇数个值为负,偶数个值为正
原理:
对于组合中每个状态有 在或不在两种,求其组合,可以用二进制枚举,也可以用递归
- 二进制
- 两层for循环
- 递归
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<iostream>
#include<iomanip>
#include<map>
#include<vector>
#include<time.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn=1e5;
const int branch=26;
const int inf=0x3f3f3f3f;
const int MOD=1e6+7;
//假设有tot个数,存储在num数组中
int num[20];//存放数字种类
int rc[maxn];//存放容斥的组合
int tot;//数字种类数
int cnt;//容斥组合的个数
void rc_for()//求出num中 tot个数的所有组合
{
cnt=0;
rc[cnt++]=1;//初始状态
for(int i=0; i<tot; ++i)
{
int k=cnt;//下标为i的数与前k个数的所有组合的组合
for(int j=0; j<k; ++j)
{
rc[cnt++]=num[i]*rc[j]*-1;//奇数个为负
}
}
}
void rc_bit()//用二进制来写
{
int top=1<<tot;//共tot个数字
cnt=0;
for(int i=0; i<top; ++i)
{
int val=1;
for(int k=0; k<tot; ++k) //枚举每个位是否为1 为1的组合整上去
{
if((1<<k)&i)
{
val*=-1*num[k];
}
}
rc[cnt++]=val;
}
}
void dfs(int k,int val)//正在枚举下标为k的状态, 之前组合乘积为-1
{
if(k==tot)
{
rc[cnt++]=val;
return ;
}
dfs(k+1,val*-1*num[k]);//下标为k的状态在组合中
dfs(k+1,val);
}
void rc_dfs()
{
cnt=0;
dfs(0,1);//
}
int main()
{
//主要是枚举这些数的所有组合(不能重复)
/*
测试
*/
scanf("%d",&tot);
for(int i=0; i<tot; ++i)
scanf("%d",num+i);
rc_for();
printf("
rc_for.........
");
cout<<"cnt:"<<cnt<<endl;
for(int i=0; i<cnt; ++i)
printf("%d ",rc[i]);
puts("");
printf("rc_bit.........
");
rc_bit();
cout<<"cnt:"<<cnt<<endl;
for(int i=0; i<cnt; ++i)
printf("%d ",rc[i]);
puts("");
rc_dfs();
cout<<"cnt:"<<cnt<<endl;
for(int i=0; i<cnt; ++i)
printf("%d ",rc[i]);
return 0;
}