[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章