Fork me on GitHub

「BZOJ3622 」已经没有什么好害怕的了 容斥 DP

Links there:BZOJ3622

题意

有 $N$ 个药和糖 每个药和糖都有自己的能量 他们之间可以两两配对 求糖的能量比药的能量大的配对数比药的能量比糖的能量大的组数恰好多 $K$ 的方案数.

思路

原题意即糖的能量比药的能量大的组数恰好为 $\frac{N+K}{2}$ 组的方案数.

先排个序 再容斥一下就好了

$f[i][j]$ 表示选择前 $i$ 个物品 组数至少为 $j$ 的方案.

$f[i][j] = \sum f[i-1][j] + f[i-1][j-1] * (k -j+1)$

注意最后统计答案的时候 那些剩下的 $n - i$ 是可以随意排列的要乘上阶乘.

Code

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
//Keep pluggin',this is your only outlet.
#include<bits/stdc++.h>
#define MM(x,y) memset(x,y,sizeof(x))
#define MCPY(a,b) memcpy(a,b,sizeof(b))
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,b,a) for(int i=b;i>=a;i--)
#define fi first
#define mp make_pair
#define se second
using namespace std;
#define int long long

inline int quickpow(int m,int n,int p){int b=1;while(n){if(n&1)b=b*m%p;n=n>>1;m=m*m%p;}return b;}
inline int quickmul(int x,int y,int mod){return (x*y-(int)((long double)x/mod*y)*mod+mod)%mod;}
inline int getinv(int x,int p){return quickpow(x,p-2,p);}
inline int read(void){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){f=ch=='-'?-1:1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x * f;
}
const int Mod = 1e9 + 9;
const int MAXN = 2e3 + 100;
int f[MAXN][MAXN],k,n,a[MAXN],b[MAXN],fac[MAXN],inv[MAXN];
inline void pre(void){
fac[0] = inv[0] = 1;
for (int i = 1; i < MAXN; ++i) fac[i] = fac[i-1] * i % Mod;
inv[MAXN-1] = getinv(fac[MAXN-1],Mod);
for (int i = MAXN-2; i >= 1; --i) inv[i] = inv[i+1] * (i + 1) % Mod;
}
inline int C(int n,int m){
if (m > n) return 0;
return fac[n] * inv[n - m] % Mod * inv[m] % Mod;
}
inline void upd(int &x,int y){x = (x + y) % Mod;}
///------------------head------------------
signed main(signed argc, char *argv[]){
//freopen("3622.in","r",stdin);
//freopen("3622.out","w",stdout);
pre();
//printf("%lld\n",C(6,2));
n = read(),k = read();
for (int i = 1; i <= n; ++i) a[i] = read();
for (int i = 1; i <= n; ++i) b[i] = read();
sort(a+1,a+n+1); sort(b+1,b+n+1);
f[0][0] = 1;
for (int i = 1,k = 0; i <= n; ++i) {
while(k < n && b[k+1] < a[i]) ++k;
for (int j = 1; j <= i; ++j) {
upd(f[i][j],f[i-1][j]);
upd(f[i][j],f[i-1][j-1] * (max(0LL,k - j + 1)) % Mod);
}
f[i][0] = f[i-1][0];
}
int nk = (n + k) >> 1,ans = 0;
for (int i = nk,d = 1; i <= n; ++i,d = Mod - d) upd(ans,f[n][i] * d % Mod * C(i,nk) % Mod * fac[n-i] % Mod);//printf("%lld\n",ans);
printf("%lld\n",ans);
return 0;
}

/* Examples: */
/*

*/

/*

*/