20230830-数学——容斥
20230830
自学容斥
OI-Wiki
\(\emptyset \in \notin \subset \supset \supseteq \subseteq \bigcap \bigcup \bigvee \bigwedge \biguplus\)
容斥原理
不定方程非负整数解计数
Statement
给出不定方程
$\sum_{i=1}^nx_i=m $和 \(n\) 个限制条件 \(x_i\leq b_i\),其中 \(m,b_i \in \mathbb{N}.\) 求方程的非负整数解的个数。
Solution
考虑没有限制时,答案就是 \(\binom{m+n-1}{n-1}\)
用插板法即可证明
容斥模型
- 全集:没有限制时所有解的方案数
- 元素:变量 \(x_i\)
- 属性:\(x_i \le b_i\)
考虑原题中的方案数是这些集合的交集 \(|\bigcap_{i=1}^{n}S_i|\)
于是用容斥原理的公式可以得到答案就是 \(|U|-|\bigcup_{i=1}^{n} \overline{S_i}|\)
而后者就可以用容斥原理来求了,
对于一些 \(\overline {S_{a_i}}\) ,我们要求他们的交集
也就是说有些需要满足下限 \(x_i \gt b_i\)
考虑如何把下限去掉——
直接剪掉就可以了:
于是我们只需要用组合数去求
长度为 \(k\) 的数组 \(a\) 也就相当于在枚举子集
P1450 [HAOI2008] 硬币购物
Statement
传送门
有4种不同面值的硬币,第 \(i\) 种面值的硬币价值为 \(C_i\)
当前每种硬币的数量为 \(d_i\) ,问有多少种购买价值为 \(S\) 的物品的方式
$ n \le 10^3,S \le 10^5$
Solution
转化一下题意:
就是求 \(\sum_{i=1}^{4} C_i x_i=S,x_i \le d_i\) 的非负整数解的数量
于是可以套用上面的容斥模型去完成
考虑对于全集 \(U\) 发现 \(S\) 很小,
所以可以直接用无限背包去完成即可
这道题主要就在于 \(4\) 十分特殊,
这也使得后面容斥时只有 \(16\) 种情况
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int c[5],n,d[5],s,m,cnt;
int ans=0,f[N];
signed main(){
/*2023.8.30 H_W_Y P1450 [HAOI2008] 硬币购物 容斥*/
scanf("%lld%lld%lld%lld%lld",&c[1],&c[2],&c[3],&c[4],&n);
f[0]=1ll;
for(int j=1;j<=4;j++)
for(int i=1;i<N;i++)
if(i>=c[j]) f[i]+=f[i-c[j]];
for(int k=1;k<=n;k++){
ans=0;
scanf("%lld%lld%lld%lld%lld",&d[1],&d[2],&d[3],&d[4],&s);
for(int i=1;i<16;i++){
m=s,cnt=0;
for(int j=1;j<=4;j++)
if((i>>(j-1))&1){
cnt++;
m-=(d[j]+1)*c[j];
}
if(m>=0) ans+=1ll*(cnt%2*2-1)*f[m];
}
printf("%lld\n",f[s]-ans);
}
return 0;
}