[BZOJ 3622]已经没有什么好害怕的了
已经……没有什么好害怕的了
OI给了我足够的欢乐了,OI让我看到了新的世界,让我有了人生中最好的几位朋友,我没有什么可以遗憾的了……就算可能要面临最残酷的结局吧……
有点跑题了呢……还是说这个题吧
显然可以看出来这个题要求你的从大到小的匹配(姑且称之为好的匹配)恰好要有n+k2个,剩下的全都不是好的匹配。
首先把糖果(记为A)和药片(记为B)分别排序,对于每一个A中元素就很容易得到B中有多少比它小的。考虑设计状态f[i][j]表示对(排序后的)A的前i项,已经确定了的好的匹配有至少j个。这个DP转移显然。
然后发现f[n][j]×(n−j)!就是对于所有元素的完美匹配中,有至少j个是好的匹配的方案数。这正是广义容斥原理的用武之地。考虑记tj=f[n][j]×(n−j)!,那么答案就是(令n+k2=l):
\sum_{i = l}^n (-1)^{n - i}\binom{i}{l} t_i
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | /************************************************************** Problem: 3622 User: danihao123 Language: C++ Result: Accepted Time:1844 ms Memory:63680 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <cstdlib> #include <cctype> #include <algorithm> #include <utility> typedef long long ll; const ll ha = 1000000009LL; const int maxn = 2005; ll C[maxn][maxn], F[maxn]; inline void process() { int N = 2000; C[0][0] = 1LL; for ( int i = 1; i <= N; i ++) { C[i][0] = C[i][i] = 1LL; for ( int j = 1; j < i; j ++) { C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % ha; } } F[0] = 1LL; for ( int i = 1; i <= N; i ++) { F[i] = (F[i - 1] * (ll(i))) % ha; } } int A[maxn], B[maxn]; ll cp[maxn]; int n; void gen_cp() { std::sort(A + 1, A + 1 + n); std::sort(B + 1, B + 1 + n); for ( int i = 1; i <= n; i ++) { cp[i] = n - (B + n + 1 - std::upper_bound(B + 1, B + 1 + n, A[i])); #ifdef LOCAL printf ( "cp[%d] : %lld\n" , i, cp[i]); #endif } } ll f[maxn][maxn]; ll dp( int dec) { process(); gen_cp(); f[0][0] = 1LL; for ( int i = 1; i <= n; i ++) { for ( int j = 0; j <= n; j ++) { f[i][j] = f[i - 1][j]; if (j > 0) { f[i][j] += (f[i - 1][j - 1] * std::max(0LL, cp[i] - ll(j - 1))) % ha; if (f[i][j] >= ha) f[i][j] -= ha; } #ifdef LOCAL printf ( "f[%d][%d] : %lld\n" , i, j, f[i][j]); #endif } } for ( int j = 0; j <= n; j ++) { f[n][j] = (f[n][j] * F[n - j]) % ha; } ll ans = 0; for ( int j = dec; j <= n; j ++) { ll a = ((j - dec) % 2 == 0) ? 1LL : (ha - 1LL); ll delta = (C[j][dec] * f[n][j]) % ha; ans += (a * delta) % ha; if (ans >= ha) ans -= ha; } return ans; } int main() { int k; scanf ( "%d%d" , &n, &k); if ((n - k) & 1) { puts ( "0" ); return 0; } for ( int i = 1; i <= n; i ++) { scanf ( "%d" , &A[i]); } for ( int i = 1; i <= n; i ++) { scanf ( "%d" , &B[i]); } printf ( "%lld\n" , dp((n + k) / 2)); return 0; } |