容斥原理
如果求交集,那么就是
不定方程的非负整数解
求不定方程 () 的非负整数解个数 满足约束条件 ()
题目要求,为没有限制的情况,直接隔板法,答案为
转化为一些有限制,一些没限制,因此
例题1
四种硬币面值为,每种硬币有个,次询问,求组成的面值方案数?
背包复杂度为
容斥做,那么,,复杂度为
cpp
void solve(){
array<int,4> c,d;
int n,s;
cin>>c[0]>>c[1]>>c[2]>>c[3]>>n;
vector<int> dp(1e5+10);
dp[0]=1;
for(int i=0;i<4;i++){
for(int j=c[i];j<=1e5;j++)dp[j]+=dp[j-c[i]];
}
while(n--){
for(int i=0;i<4;i++)cin>>d[i];
cin>>s;
int ans=dp[s],res=0;
for(int i=1;i<1<<4;i++){// 如果从0开始,那么可以发现是偶正奇反
int ss=s,cnt=0;
for(int j=0;j<4;j++){
if(i>>j&1){
cnt++;
ss-=c[j]*(d[j]+1);
}
}
if(ss<0)continue;
res+=((cnt&1)?1:-1)*dp[ss];
}
cout<<ans-res<<"\n";
}
}注意到可以从0开始枚举状态,因此可以转变为:所有满足限制的方案=有个违反限制的方案
CCPC2021威海M
长度为的01序列,求恰好有个,连续段最长恰好为的方案数
经典trick:表示小于等于的方案,答案就是
考虑求,把看成隔板,就是求
因为所有限制条件相同,因此,直接枚举有个违反了限制