[BZOJ3622] 已经没有什么好害怕的了 [容斥原理][二项式反演]

[Link\frak{Link}]


容斥基本形式 UA1A2An=SA(1)SUS1S2SS\mathrm{|U\cap\overline{A_1}\cap\overline{A_2}\cap\cdots\cap\overline{A_n}|=\sum\limits_{S\subseteq A}(-1)^{|S|}|U\cap S_1\cap S_2\cap\cdots\cap S_{|S|}|}
反演基本形式 fn=i=0nanigign=i=0nbnifif_n=\sum\limits_{i=0}^na_{ni}g_i\Leftrightarrow g_n=\sum\limits_{i=0}^nb_{ni}f_i
也可以说是: F=AGG=BF\mathbf F=\mathbf{AG}\Leftrightarrow \mathbf G=\mathbf{BF} 。则 B=A1=AA\mathbf B=\mathbf A^{-1} = \dfrac{\mathbf A^*}{|\mathbf A|}
(矩阵求逆暴力一点可以用高斯消元,把 [AE][\mathbf{A|E}] 变成 [EB][\mathbf{E|B}] 。不过反演一般不会这么搞)
反演成立的充要条件 j=inanjbji=[i=j]\sum\limits_{j=i}^na_{nj}b_{ji}=[i=j]


二项式定理 (a+b)n=r=0n(nr)aibnr(a+b)^n=\sum\limits_{r=0}^n{n\choose r}a^ib^{n-r}
二项式反演 gn=i=0n(1)i(ni)fifn=i=0n(1)i(ni)gig_n=\sum\limits_{i=0}^n(-1)^i{n\choose i}f_i\Leftrightarrow f_n=\sum\limits_{i=0}^n(-1)^i{n\choose i}g_i
至多↔恰好 gn=i=0n(ni)fifn=i=0n(1)ni(ni)gig_n=\sum\limits_{i=0}^n{n\choose i}f_i\Leftrightarrow f_n=\sum\limits_{i=0}^n(-1)^{n-i}{n\choose i}g_i
至少↔恰好 gi=j=in(ji)fjfi=j=in(1)ji(ji)gjg_i=\sum\limits_{j=i}^n{j\choose i}f_j\Leftrightarrow f_i=\sum\limits_{j=i}^n(-1)^{j-i}{j\choose i}g_j


一个套路:由 gn=i=0n1(ni)fi+fng_n=\sum\limits_{i=0}^{n-1}{n\choose i}f_i+f_n 得到 fn=gni=0n1(ni)fif_n=g_n-\sum\limits_{i=0}^{n-1}{n\choose i}f_i 就可以用 ggff
如果继续拆就可以由原式推出反演。
fn=gn(nn1)fn1i=0n2(ni)fif_n=g_n-{n\choose n-1}f_{n-1}-\sum\limits_{i=0}^{n-2}{n\choose i}f_i
fn=gn(nn1)gn1+(nn1)i=0n2(n1i)fii=0n2(ni)fif_n=g_n-{n\choose n-1}g_{n-1}+{n\choose n-1}\sum\limits_{i=0}^{n-2}{n-1\choose i}f_i-\sum\limits_{i=0}^{n-2}{n\choose i}f_{i}
fn=gn(nn1)gn1+i=0n2[(nn1)(n1i)fi(ni)fi]f_n=g_n-{n\choose n-1}g_{n-1}+\sum\limits_{i=0}^{n-2}\left[{n\choose n-1}{n-1\choose i}f_i-{n\choose i}f_i\right]
fn=gn(nn1)gn1+i=0n2[(ni)(nin1i)fi(ni)fi]f_n=g_n-{n\choose n-1}g_{n-1}+\sum\limits_{i=0}^{n-2}\left[{n\choose i}{n-i\choose n-1-i}f_i-{n\choose i}f_i\right]
fn=gn(nn1)gn1+i=0n2(ni)(ni1)fif_n=g_n-{n\choose n-1}g_{n-1}+\sum\limits_{i=0}^{n-2}{n\choose i}(n-i-1)f_i
fn=gn(nn1)gn1+(nn2)gn2i=0n3(n2i)fi+i=0n3(ni)(ni1)fif_n=g_n-{n\choose n-1}g_{n-1}+{n\choose n-2}g_{n-2}-\sum\limits_{i=0}^{n-3}{n-2\choose i}f_i+\sum\limits_{i=0}^{n-3}{n\choose i}(n-i-1)f_i
一直展开下去,猜想会得到 fn=i=0n(1)ni(ni)gif_n=\sum\limits_{i=0}^n(-1)^{n-i}{n\choose i}g_i 。证明一下,的确是。

遇到新的反演就可以这么推试试看(相信应该还有更好的方法,但是我实在找不到了)
不嫌麻烦的话说不定可以手模矩阵求逆,但是风险还比较大((


二项式反演是组合数形式的容斥。
在集合 U\mathrm U 中,有 nn 个具有不同性质元素的集合 A1,A2, ,An\mathrm{A_1,A_2,\cdots,A_n}
考虑容斥的特殊情况:集族 Q={A1,A2, ,An}\mathrm{Q=\{A_1,A_2,\cdots,A_n\}} 中任意 ii 个集合的并集大小为 gig_i

那么 gi=A1A2Aig_i=\mathrm{|A_1\cap A_2\cap\cdots\cap A_i|} ,在 Q\mathrm Q 中有 (ni)n\choose i 个这样的不同交集。定义 g0=Ug_0=|\mathrm U|
由容斥原理有 A1A2An=USA(1)SS1S2SS\mathrm{|\overline{A_1}\cap\overline{A_2}\cap\cdots\cap\overline{A_n}|=|U|-\sum\limits_{S\subseteq A}(-1)^{|S|}|S_1\cap S_2\cap\cdots\cap S_{|S|}|}
fn=A1A2An=i=0n(1)i(ni)gif_n=\mathrm{|\overline{A_1}\cap\overline{A_2}\cap\cdots\cap\overline{A_n}|=}\sum\limits_{i=0}^n(-1)^i{n\choose i}g_i
定义 fi=A1A2Aif_i=\mathrm{|\overline{A_1}\cap\overline{A_2}\cap\cdots\cap\overline{A_i}|}f0=Uf_0=|\mathrm U| ,有
gn=A1A2An=i=0n(1)i(ni)fig_n=\mathrm{|A_1\cap A_2\cap\cdots\cap A_n|=}\sum\limits_{i=0}^n(-1)^i{n\choose i}f_i


首先为了方便把两个数组分别从小到大排序。

假设计数时的某种情况下糖果 aia_i ,药片 bjb_{j}i,jni,j\le n
题目要求计数的是 i=1n[ai>bi]=i=1n[bi>ai]+k\sum\limits_{i=1}^n[a_i>b_i]=\sum\limits_{i=1}^n[b_i>a_i]+k 的情况数。


想容斥:固定前面的一部分,然后后面的一部分容斥。
考虑安排 bi>aib_i>a_i 一类的,可以对每个 aia_i 预处理 bjb_j 到哪里为止都小于 aia_i ,存为 sis_{i}
安排的时候固定 aabb 中的一组,只拿另一组去配对 。

前面一部分可以算:到 ii 为止,配对了 jjax>bxa_x>b_xxix\le i)的方案数 ti,jt_{i,j}
(没有配对的部分啥都没有)

ti,j=ti1,j+[gi>j1][(sij+1)ti1,j1]t_{i,j}=t_{i-1,j}+[g_i>j-1][(s_i-j+1)t_{i-1,j-1}]
nn 为止, 至少iiax>bxa_x>b_x 的方案数,设为 fif_{i } ,有 fi=tn,i(ni)!f_{i}=t_{n,i}(n-i)!

“ 至少 ” 容易求,考虑二项式反演。把原问题转化成求:
nn 为止, 恰好n+k2\frac{n+k}{2}ax>bxa_x>b_x 的方案数。(n+kn+k 为奇数要讨论)


要知道答案,首先要知道到 nn 为止 恰好iiax>bxa_x>b_x 的方案数。设为 gig_{i}

考虑一下 gjg_jfif_i 的关系 (ijni\le j\le n)。gjg_j 可能会在 fif_i 里面被多算。算了几次?
gjg_jjjax>bxa_x>b_xtn,it_{n,i} 要求包含 iiax>bxa_x>b_x
jj 对里面选 ii 对,那么 gjg_jtn,it_{n,i} 的贡献是 (ji)j\choose i 。所以 gjg_jfif_i 的贡献就是 (ji)j\choose i


按照减去多算的部分的思路, gi=fij=i+1n(ji)gjg_i=f_i-\sum\limits_{j=i+1}^n{j\choose i}g_j


如果考虑到 fi=j=in(ji)gjf_i=\sum\limits_{j=i}^n{j\choose i}g_j 就可以二项式反演 gi=j=in(1)ji(ji)fjg_i=\sum\limits_{j=i}^n(-1)^{j-i}{j\choose i}f_j
不知道也可以做,把 gig_i 从和号里面拆出来,稍作变换得 gi=fij=i+1n(ji)gjg_i=f_i-\sum\limits_{j=i+1}^n{j\choose i}g_j


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cctype>
#include <cmath>
using namespace std;
const long long MOD = 1000000009ll;
int n, k, m;
long long a[2005], b[2005];
long long c[2005][2005], f[2005], p[2005];
#define adjust(x) (x>=MOD)?(x-MOD):x
int main() {
	scanf("%d%d", &n, &k);
	if (n + k & 1) return printf("0"), 0;
	for (register int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
	for (register int i = 1; i <= n; ++i) scanf("%lld", &b[i]);
	for (register int i = 0, j; i <= n; ++i) {
		for (j = 1, c[i][0] = 1; j <= i; ++j) {
			c[i][j] = adjust(c[i-1][j-1] + c[i-1][j]);
		}
	}
	p[0] = 1ll;
	for (register int i = 1; i <= n; ++i) {
		p[i] = 1ll * i * p[i-1] % MOD;
	}
	sort(a+1, a+1+n);
	sort(b+1, b+1+n);
	f[0] = 1ll;
	for (register int z = 1, i = 1, j; i <= n; ++i) {
		while (z <= n && a[i] > b[z]) ++z;
		for (--z, j = i; j >= 1; --j) {
			f[j] = (f[j] + f[j - 1] * max(0, z - j + 1)) % MOD;
		}
	}
	m = n + k >> 1;
	for (register int i = n; i >= m; --i) {
		f[i] = f[i] * p[n - i] % MOD;
		for (register int j = i + 1; j <= n; ++j) {
			f[i] = (f[i] - c[j][i] * f[j] % MOD + MOD) % MOD;
		}
	}
	printf("%lld",f[m]);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章