20230830-数学——容斥

20230830
自学容斥
OI-Wiki
\(\emptyset \in \notin \subset \supset \supseteq \subseteq \bigcap \bigcup \bigvee \bigwedge \biguplus\)

容斥原理

\[|\bigcup_{i=1}^{n}S_i|=\sum_{m=1}^{n}(-1)^{m-1}\sum_{a_i \lt a_{i+1}}|\bigcap_{i=1}^{m}S_{a_i}|\\ |\bigcap_{i=1}^{n}S_i|=|U|-|\bigcup_{i=1}^{n}\overline{S_i}| \]

不定方程非负整数解计数

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}\)
用插板法即可证明

容斥模型

  1. 全集:没有限制时所有解的方案数
  2. 元素:变量 \(x_i\)
  3. 属性:\(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\)
考虑如何把下限去掉——
直接剪掉就可以了:
于是我们只需要用组合数去求

\[\sum_{i=1}^{n}x_i=m-\sum_{i=1}^{k}(b_{a_i}+1) \]

长度为 \(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;
}
posted @ 2023-08-30 15:45  H_W_Y  阅读(31)  评论(0编辑  收藏  举报