[BZOJ 3622] 已经没有什么好害怕的了 手动反演
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ 3622] 已经没有什么好害怕的了 手动反演相关的知识,希望对你有一定的参考价值。
题意
给定两个大小为 n 的集合 A = {a[1], a[2], ..., a[n]} , B = {b[1], b[2], ..., b[n]} , 元素两两不同.
定义 L(A) 为 A 生成的排列的集合.
给定 K , 求 $\sum_{X \in L(A), Y \in L(B)} [\sum_{k = 1} ^ n [X_k > Y_k] - \sum_{k = 1} ^ n [X_k < Y_k] = K]$ .
1 <= n <= 2000, 0 <= K <= n .
分析
令 $K = \frac{n + K}{2}$ , 求恰好存在 K 个 X[i] > Y[i] 的排列有多少对.
设 f[i] 表示钦定有 i 个位, X[i] > Y[i] , 并且不考虑其他位.
f[i] 可以通过 DP 求得.
F[i][j] = F[i-1][j] + F[i-1][j-1] * (cnt[i] - (j-1)) .
不能直接用 f[K] * (n-K)! + f[K+1] * (n-(K+1))! - ...
因为从第二项开始算的次数都不是一次, 而是一个谜之二项式系数的乘积的和.
设 g[i] 表示恰好有 i 个位, X[i] > Y[i] .
g[n] = f[n] .
$g[i] = f[i] - \sum_{j = i+1} ^ n g[j] \binom{j}{i}$ .
这里的做法, 与 "手动的莫比乌斯反演" 是一个原理.
小结
对于这类恰好有 K 个位的问题, 我们可以考虑手动反演.
G[K] 表示恰好有 K 个位, F[K] 表示钦定有 K 个位.
G[n] = F[n] .
G[i] = F[i] - ∑ G[j] * 迷之系数.
实现
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include <algorithm> 6 using namespace std; 7 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 8 #define P(i, a, b) for (register int i = (a); i >= (b); i--) 9 inline int rd(void) { 10 int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -1; 11 int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-‘0‘; return x*f; 12 } 13 14 const int N = 2005; 15 const int MOD = (int)1e9 + 9; 16 17 int n, K, C[N][N], fac[N], A[N], B[N], cnt[N]; 18 int f[N], g[N]; 19 20 int main(void) { 21 #ifndef ONLINE_JUDGE 22 freopen("bzoj3622.in", "r", stdin); 23 #endif 24 25 n = rd(), K = rd(); 26 if ((K + n) & 1) return puts("0"), 0; 27 K = (K + n) >> 1; 28 29 F(i, 0, n) { 30 C[i][0] = 1; 31 F(j, 1, i) 32 C[i][j] = (C[i-1][j] + C[i-1][j-1]) % MOD; 33 } 34 fac[0] = 1; 35 F(i, 1, n) fac[i] = 1LL * fac[i-1] * i % MOD; 36 37 F(i, 1, n) A[i] = rd(); F(i, 1, n) B[i] = rd(); 38 sort(A+1, A+n+1), sort(B+1, B+n+1); 39 for (int cur = 1, _cur = 0; cur <= n; cur++) { 40 while (_cur+1 <= n && B[_cur+1] < A[cur]) 41 _cur++; 42 cnt[cur] = _cur; 43 } 44 45 f[0] = 1; 46 F(i, 1, n) 47 P(j, i, 1) 48 f[j] = (f[j] + 1LL * f[j-1] * (cnt[i] - (j-1))) % MOD; 49 50 g[n] = f[n]; 51 P(i, n-1, K) { 52 g[i] = 1LL * f[i] * fac[n-i] % MOD; 53 F(j, i+1, n) 54 g[i] = (g[i] - 1LL * g[j] * C[j][i]) % MOD; 55 } 56 printf("%d\n", (g[K] + MOD) % MOD); 57 58 return 0; 59 }
以上是关于[BZOJ 3622] 已经没有什么好害怕的了 手动反演的主要内容,如果未能解决你的问题,请参考以下文章