bzoj3622

容斥原理

看见恰好k个就要容斥

g[i]表示有几个b比a小

dp[i][j]表示前i个数至少有j个大的方案数,dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(g[i]-j+1),就是可以不匹配,或者在剩下的g[i]-j+1选一个

然后就是容斥了,那个系数搞的不是很清楚,和spring一样

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2005, P = 1e9 + 9;
int n, k;
ll ans;
ll a[N], b[N], inv[N], facinv[N], fac[N], dp[N][N], g[N];
ll C(int n, int m)
{
    return fac[n] * facinv[m] % P * facinv[n - m] % P;  
}
int main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for(int i = 1; i <= n; ++i) scanf("%d", &b[i]);
    if((n + k) & 1) 
    {
        puts("0");
        return 0;
    }
    k += (n - k) >> 1;
    sort(a + 1, a + n + 1);
    sort(b + 1, b + n + 1);
    inv[1] = 1; fac[0] = facinv[0] = 1;
    for(int i = 1; i <= n; ++i)
    {
        if(i != 1) inv[i] = (P - P / i) * inv[P % i] % P;
        facinv[i] = facinv[i - 1] * inv[i] % P;
        fac[i] = fac[i - 1] * i % P;
    }
    for(int i = 1, j = 0; i <= n; ++i) 
    {
        while(a[i] > b[j + 1] && j + 1 <= n) ++j;
        g[i] = j;
    }
    for(int i = 0; i <= n; ++i) dp[i][0] = 1;
    for(int i = 1; i <= n; ++i) 
        for(int j = 1; j <= g[i]; ++j) 
            dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1] * (g[i] - j + 1) % P) % P;
    for(int i = k; i <= n; ++i) ans = ((ans + (((i - k) & 1) ? -1 : 1) * dp[n][i] * fac[n - i] % P * C(i, k) % P) % P + P) % P;
    printf("%lld\n", ans);
    return 0;
}
View Code

 

posted @ 2017-12-12 09:47  19992147  阅读(156)  评论(0编辑  收藏  举报