BZOJ - Problem 3622 - 已经没有什么好害怕的了

题意:

  给定两个序列ab,让它们进行匹配,求出使得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 */
View Code

猜你喜欢

转载自www.cnblogs.com/Colythme/p/9697675.html