码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ 3622] 已经没有什么好害怕的了 手动反演

时间:2017-08-19 21:17:56      阅读:147      评论:0      收藏:0      [点我收藏+]

标签:git   题意   getchar   lin   [1]   生成   register   div   reg   

题意

  给定两个大小为 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] 已经没有什么好害怕的了 手动反演

标签:git   题意   getchar   lin   [1]   生成   register   div   reg   

原文地址:http://www.cnblogs.com/Sdchr/p/7397720.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!