题意:
给定两个序列a和b,让它们进行匹配,求出使得ai > bi的个数比ai < bj的个数恰好多k,求这样的匹配方法数
题解:
这题的各种表示有一点相似又截然不同,很容易混淆。
直接求恰好满足k对不好求,所以先放宽条件,这样子有利于构造动规方程。
先用ƒi,j表示在前i个中,至少选择j个a > b的匹配的方案数(是匹配的方案数,只关心匹配那一部分,不关心其它的部分),容易得到动规方程:
ƒi,j = ƒi - 1,j + (Lasti - (j - 1)) * ƒi - 1,j - 1
其中Lasti表示第一个小于ai的bj。
(Lasti - (j - 1))表示原有Lasti种选择,被选走了j - 1种,此时因为是“至少”,所以其它的匹配是不用管的。
那么现在考虑求出恰好为k的方案数。
首先令gi表示前N个a中,满足至少有i个a > b的方案数,那么
gi = ƒN,j * (N - i) !
这时候才考虑了其它的部分,所以需要乘上阶乘。
再令ƒ'i表示恰好满足i组的方案数,那么考虑容斥,在所有的gj中,每个ƒ'i (i > j)被算了Ci, j次,因为不考虑其它的,仅i个已匹配好的任意取j个,其它的随便排,正好被gj囊括,当然这一部分是多余的,所以
ƒ'i = gj - Cj, i * ƒ'j (j > i)
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 #define MOD 1000000009 7 8 using namespace std; 9 10 typedef long long LL; 11 12 const int MAXN = 2000 + 10; 13 14 LL g[MAXN][MAXN]; 15 16 LL f[MAXN]= {0}; 17 18 LL fac[MAXN]; 19 LL C[MAXN][MAXN]; 20 21 int N, K; 22 23 int Candy[MAXN], Pill[MAXN]; 24 25 int Last[MAXN]= {0}; 26 27 void Preparation () { 28 fac[0] = 1; 29 for (int i = 1; i <= N; i ++) 30 fac[i] = fac[i - 1] * i % MOD; 31 32 for (int i = 0; i <= N; i ++) 33 C[i][0] = 1; 34 for (int i = 1; i <= N; i ++) 35 for (int j = 1; j <= i; j ++) 36 C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD; 37 } 38 39 int main () { 40 scanf ("%d%d", & N, & K); 41 42 Preparation (); 43 44 for (int i = 1; i <= N; i ++) 45 scanf ("%d", & Candy[i]); 46 for (int i = 1; i <= N; i ++) 47 scanf ("%d", & Pill[i]); 48 49 sort (Candy + 1, Candy + N + 1); 50 sort (Pill + 1, Pill + N + 1); 51 52 for (int i = 1; i <= N; i ++) 53 for (int j = N; j >= 1; j --) 54 if (Pill[j] < Candy[i]) { 55 Last[i] = j; 56 break; 57 } 58 59 for (int i = 0; i <= N; i ++) 60 g[i][0] = 1; 61 for (int i = 1; i <= N; i ++) 62 for (int j = 1; j <= i; j ++) 63 g[i][j] = (g[i - 1][j] + (Last[i] - j + 1) * g[i - 1][j - 1] % MOD) % MOD; 64 65 for (int i = N; i >= 1; i --) { 66 f[i] = g[N][i] * fac[N - i] % MOD; 67 for (int j = i + 1; j <= N; j ++) 68 f[i] = ((f[i] - C[j][i] * f[j] % MOD) % MOD + MOD) % MOD; 69 } 70 71 printf ("%lld\n", f[(N + K) >> 1]); 72 73 return 0; 74 } 75 76 /* 77 4 2 78 5 35 15 45 79 40 20 10 30 80 */