[L i n k \frak{Link} L i n k ]
容斥基本形式 ∣ U ∩ A 1 ‾ ∩ A 2 ‾ ∩ ⋯ ∩ A n ‾ ∣ = ∑ S ⊆ A ( − 1 ) ∣ S ∣ ∣ U ∩ S 1 ∩ S 2 ∩ ⋯ ∩ S ∣ S ∣ ∣ \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|}|} ∣ U ∩ A 1 ∩ A 2 ∩ ⋯ ∩ A n ∣ = S ⊆ A ∑ ( − 1 ) ∣ S ∣ ∣ U ∩ S 1 ∩ S 2 ∩ ⋯ ∩ S ∣ S ∣ ∣
反演基本形式 f n = ∑ i = 0 n a n i g i ⇔ g n = ∑ i = 0 n b n i f i f_n=\sum\limits_{i=0}^na_{ni}g_i\Leftrightarrow g_n=\sum\limits_{i=0}^nb_{ni}f_i f n = i = 0 ∑ n a n i g i ⇔ g n = i = 0 ∑ n b n i f i
也可以說是: F = A G ⇔ G = B F \mathbf F=\mathbf{AG}\Leftrightarrow \mathbf G=\mathbf{BF} F = A G ⇔ G = B F 。則 B = A − 1 = A ∗ ∣ A ∣ \mathbf B=\mathbf A^{-1} = \dfrac{\mathbf A^*}{|\mathbf A|} B = A − 1 = ∣ A ∣ A ∗ 。
(矩陣求逆暴力一點可以用高斯消元,把 [ A ∣ E ] [\mathbf{A|E}] [ A ∣ E ] 變成 [ E ∣ B ] [\mathbf{E|B}] [ E ∣ B ] 。不過反演一般不會這麼搞)
反演成立的充要條件 ∑ j = i n a n j b j i = [ i = j ] \sum\limits_{j=i}^na_{nj}b_{ji}=[i=j] j = i ∑ n a n j b j i = [ i = j ]
二項式定理 ( a + b ) n = ∑ r = 0 n ( n r ) a i b n − r (a+b)^n=\sum\limits_{r=0}^n{n\choose r}a^ib^{n-r} ( a + b ) n = r = 0 ∑ n ( r n ) a i b n − r
二項式反演 g n = ∑ i = 0 n ( − 1 ) i ( n i ) f i ⇔ f n = ∑ i = 0 n ( − 1 ) i ( n i ) g i g_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 g n = i = 0 ∑ n ( − 1 ) i ( i n ) f i ⇔ f n = i = 0 ∑ n ( − 1 ) i ( i n ) g i
至多↔恰好 g n = ∑ i = 0 n ( n i ) f i ⇔ f n = ∑ i = 0 n ( − 1 ) n − i ( n i ) g i g_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 g n = i = 0 ∑ n ( i n ) f i ⇔ f n = i = 0 ∑ n ( − 1 ) n − i ( i n ) g i
至少↔恰好 g i = ∑ j = i n ( j i ) f j ⇔ f i = ∑ j = i n ( − 1 ) j − i ( j i ) g j g_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 g i = j = i ∑ n ( i j ) f j ⇔ f i = j = i ∑ n ( − 1 ) j − i ( i j ) g j
一個套路:由 g n = ∑ i = 0 n − 1 ( n i ) f i + f n g_n=\sum\limits_{i=0}^{n-1}{n\choose i}f_i+f_n g n = i = 0 ∑ n − 1 ( i n ) f i + f n 得到 f n = g n − ∑ i = 0 n − 1 ( n i ) f i f_n=g_n-\sum\limits_{i=0}^{n-1}{n\choose i}f_i f n = g n − i = 0 ∑ n − 1 ( i n ) f i 就可以用 g g g 推 f f f 。
如果繼續拆就可以由原式推出反演。
f n = g n − ( n n − 1 ) f n − 1 − ∑ i = 0 n − 2 ( n i ) f i f_n=g_n-{n\choose n-1}f_{n-1}-\sum\limits_{i=0}^{n-2}{n\choose i}f_i f n = g n − ( n − 1 n ) f n − 1 − i = 0 ∑ n − 2 ( i n ) f i
f n = g n − ( n n − 1 ) g n − 1 + ( n n − 1 ) ∑ i = 0 n − 2 ( n − 1 i ) f i − ∑ i = 0 n − 2 ( n i ) f i f_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} f n = g n − ( n − 1 n ) g n − 1 + ( n − 1 n ) i = 0 ∑ n − 2 ( i n − 1 ) f i − i = 0 ∑ n − 2 ( i n ) f i
f n = g n − ( n n − 1 ) g n − 1 + ∑ i = 0 n − 2 [ ( n n − 1 ) ( n − 1 i ) f i − ( n i ) f i ] 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] f n = g n − ( n − 1 n ) g n − 1 + i = 0 ∑ n − 2 [ ( n − 1 n ) ( i n − 1 ) f i − ( i n ) f i ]
f n = g n − ( n n − 1 ) g n − 1 + ∑ i = 0 n − 2 [ ( n i ) ( n − i n − 1 − i ) f i − ( n i ) f i ] 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] f n = g n − ( n − 1 n ) g n − 1 + i = 0 ∑ n − 2 [ ( i n ) ( n − 1 − i n − i ) f i − ( i n ) f i ]
f n = g n − ( n n − 1 ) g n − 1 + ∑ i = 0 n − 2 ( n i ) ( n − i − 1 ) f i f_n=g_n-{n\choose n-1}g_{n-1}+\sum\limits_{i=0}^{n-2}{n\choose i}(n-i-1)f_i f n = g n − ( n − 1 n ) g n − 1 + i = 0 ∑ n − 2 ( i n ) ( n − i − 1 ) f i
f n = g n − ( n n − 1 ) g n − 1 + ( n n − 2 ) g n − 2 − ∑ i = 0 n − 3 ( n − 2 i ) f i + ∑ i = 0 n − 3 ( n i ) ( n − i − 1 ) f i f_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 f n = g n − ( n − 1 n ) g n − 1 + ( n − 2 n ) g n − 2 − i = 0 ∑ n − 3 ( i n − 2 ) f i + i = 0 ∑ n − 3 ( i n ) ( n − i − 1 ) f i
一直展開下去,猜想會得到 f n = ∑ i = 0 n ( − 1 ) n − i ( n i ) g i f_n=\sum\limits_{i=0}^n(-1)^{n-i}{n\choose i}g_i f n = i = 0 ∑ n ( − 1 ) n − i ( i n ) g i 。證明一下,的確是。
遇到新的反演就可以這麼推試試看(相信應該還有更好的方法,但是我實在找不到了)
不嫌麻煩的話說不定可以手模矩陣求逆,但是風險還比較大((
二項式反演是組合數形式的容斥。
在集合 U \mathrm U U 中,有 n n n 個具有不同性質元素的集合 A 1 , A 2 , ⋯  , A n \mathrm{A_1,A_2,\cdots,A_n} A 1 , A 2 , ⋯ , A n
考慮容斥的特殊情況:集族 Q = { A 1 , A 2 , ⋯  , A n } \mathrm{Q=\{A_1,A_2,\cdots,A_n\}} Q = { A 1 , A 2 , ⋯ , A n } 中任意 i i i 個集合的並集大小爲 g i g_i g i 。
那麼 g i = ∣ A 1 ∩ A 2 ∩ ⋯ ∩ A i ∣ g_i=\mathrm{|A_1\cap A_2\cap\cdots\cap A_i|} g i = ∣ A 1 ∩ A 2 ∩ ⋯ ∩ A i ∣ ,在 Q \mathrm Q Q 中有 ( n i ) n\choose i ( i n ) 個這樣的不同交集。定義 g 0 = ∣ U ∣ g_0=|\mathrm U| g 0 = ∣ U ∣ 。
由容斥原理有 ∣ A 1 ‾ ∩ A 2 ‾ ∩ ⋯ ∩ A n ‾ ∣ = ∣ U ∣ − ∑ S ⊆ A ( − 1 ) ∣ S ∣ ∣ S 1 ∩ S 2 ∩ ⋯ ∩ S ∣ S ∣ ∣ \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|}|} ∣ A 1 ∩ A 2 ∩ ⋯ ∩ A n ∣ = ∣ U ∣ − S ⊆ A ∑ ( − 1 ) ∣ S ∣ ∣ S 1 ∩ S 2 ∩ ⋯ ∩ S ∣ S ∣ ∣
f n = ∣ A 1 ‾ ∩ A 2 ‾ ∩ ⋯ ∩ A n ‾ ∣ = ∑ i = 0 n ( − 1 ) i ( n i ) g i f_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 f n = ∣ A 1 ∩ A 2 ∩ ⋯ ∩ A n ∣ = i = 0 ∑ n ( − 1 ) i ( i n ) g i
定義 f i = ∣ A 1 ‾ ∩ A 2 ‾ ∩ ⋯ ∩ A i ‾ ∣ f_i=\mathrm{|\overline{A_1}\cap\overline{A_2}\cap\cdots\cap\overline{A_i}|} f i = ∣ A 1 ∩ A 2 ∩ ⋯ ∩ A i ∣ , f 0 = ∣ U ∣ f_0=|\mathrm U| f 0 = ∣ U ∣ ,有
g n = ∣ A 1 ∩ A 2 ∩ ⋯ ∩ A n ∣ = ∑ i = 0 n ( − 1 ) i ( n i ) f i g_n=\mathrm{|A_1\cap A_2\cap\cdots\cap A_n|=}\sum\limits_{i=0}^n(-1)^i{n\choose i}f_i g n = ∣ A 1 ∩ A 2 ∩ ⋯ ∩ A n ∣ = i = 0 ∑ n ( − 1 ) i ( i n ) f i
首先爲了方便把兩個數組分別從小到大排序。
假設計數時的某種情況下糖果 a i a_i a i ,藥片 b j b_{j} b j 。 i , j ≤ n i,j\le n i , j ≤ n 。
題目要求計數的是 ∑ i = 1 n [ a i > b i ] = ∑ i = 1 n [ b i > a i ] + k \sum\limits_{i=1}^n[a_i>b_i]=\sum\limits_{i=1}^n[b_i>a_i]+k i = 1 ∑ n [ a i > b i ] = i = 1 ∑ n [ b i > a i ] + k 的情況數。
想容斥:固定前面的一部分,然後後面的一部分容斥。
考慮安排 b i > a i b_i>a_i b i > a i 一類的,可以對每個 a i a_i a i 預處理 b j b_j b j 到哪裏爲止都小於 a i a_i a i ,存爲 s i s_{i} s i 。
安排的時候固定 a a a 和 b b b 中的一組,只拿另一組去配對 。
前面一部分可以算:到 i i i 爲止,配對了 j j j 對 a x > b x a_x>b_x a x > b x (x ≤ i x\le i x ≤ i )的方案數 t i , j t_{i,j} t i , j 。
(沒有配對的部分啥都沒有)
有 t i , j = t i − 1 , j + [ g i > j − 1 ] [ ( s i − j + 1 ) t i − 1 , j − 1 ] t_{i,j}=t_{i-1,j}+[g_i>j-1][(s_i-j+1)t_{i-1,j-1}] t i , j = t i − 1 , j + [ g i > j − 1 ] [ ( s i − j + 1 ) t i − 1 , j − 1 ] 。
到 n n n 爲止, 至少 有 i i i 對 a x > b x a_x>b_x a x > b x 的方案數,設爲 f i f_{i
} f i ,有 f i = t n , i ( n − i ) ! f_{i}=t_{n,i}(n-i)! f i = t n , i ( n − i ) ! 。
“ 至少 ” 容易求,考慮二項式反演。把原問題轉化成求:
到 n n n 爲止, 恰好 有 n + k 2 \frac{n+k}{2} 2 n + k 對 a x > b x a_x>b_x a x > b x 的方案數。(n + k n+k n + k 爲奇數要討論)
要知道答案,首先要知道到 n n n 爲止 恰好 有 i i i 對 a x > b x a_x>b_x a x > b x 的方案數。設爲 g i g_{i} g i 。
考慮一下 g j g_j g j 和 f i f_i f i 的關係 (i ≤ j ≤ n i\le j\le n i ≤ j ≤ n )。g j g_j g j 可能會在 f i f_i f i 裏面被多算。算了幾次?
g j g_j g j 有 j j j 對 a x > b x a_x>b_x a x > b x ; t n , i t_{n,i} t n , i 要求包含 i i i 對 a x > b x a_x>b_x a x > b x 。
j j j 對裏面選 i i i 對,那麼 g j g_j g j 對 t n , i t_{n,i} t n , i 的貢獻是 ( j i ) j\choose i ( i j ) 。所以 g j g_j g j 對 f i f_i f i 的貢獻就是 ( j i ) j\choose i ( i j ) 。
按照減去多算的部分的思路, g i = f i − ∑ j = i + 1 n ( j i ) g j g_i=f_i-\sum\limits_{j=i+1}^n{j\choose i}g_j g i = f i − j = i + 1 ∑ n ( i j ) g j 。
如果考慮到 f i = ∑ j = i n ( j i ) g j f_i=\sum\limits_{j=i}^n{j\choose i}g_j f i = j = i ∑ n ( i j ) g j 就可以二項式反演 g i = ∑ j = i n ( − 1 ) j − i ( j i ) f j g_i=\sum\limits_{j=i}^n(-1)^{j-i}{j\choose i}f_j g i = j = i ∑ n ( − 1 ) j − i ( i j ) f j 。
不知道也可以做,把 g i g_i g i 從和號裏面拆出來,稍作變換得 g i = f i − ∑ j = i + 1 n ( j i ) g j g_i=f_i-\sum\limits_{j=i+1}^n{j\choose i}g_j g i = f i − j = i + 1 ∑ n ( i j ) 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 ;
}