bzoj3622 已经没有什么好害怕的了

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3622

【题解】

XJOI noip模拟题的一题吧

这题统计方法用容斥

f[i,j]表示前i个人,j个一定赢,其他不管的方案数。

先考虑一定赢的转移,最后乘不论输赢的排列即可。

那么ans[n] = f[n,n]

ans[i] = f[n,i] - sigma(ans[j] * C(j,i)),其中j>i

j个人赢了,挑任意i个人出来都符合条件,减去

最后答案为ans[nWin]。

# include <vector>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 2e3 + 10;
const int mod = 1e9+9;

# define RG register
# define ST static

int n, K, a[M], b[M];
int f[M][M], C[M][M], fac[M], ok[M], ans[M];

int main() {
    cin >> n >> K;
    if((n+K)&1) {
        puts("0");
        return 0;
    }
    fac[0] = 1; 
    for (int i=1; i<=n; ++i) fac[i] = 1ll * fac[i-1] * i % mod; 
    C[0][0] = 1;
    for (int i=1; i<=n; ++i) {
        C[i][0] = 1; 
        for (int j=1; j<=i; ++j) { 
            C[i][j] = C[i-1][j] + C[i-1][j-1]; 
            if(C[i][j] >= mod) C[i][j] -= mod;
        }
    }
    for (int i=1; i<=n; ++i) scanf("%d", a+i);
    for (int i=1; i<=n; ++i) scanf("%d", b+i);
    int nWin = (n+K)/2, nLose = (n-K)/2;
    sort(a+1, a+n+1); 
    sort(b+1, b+n+1);
    for (int i=1; i<=n; ++i) ok[i] = upper_bound(b+1, b+n+1, a[i]) - b - 1; 
    f[0][0] = 1; 
    for (int i=1; i<=n; ++i) { 
        for (int j=0; j<=i; ++j) {
            f[i][j] = f[i-1][j];
            if(j && ok[i]-(j-1) > 0) {
                f[i][j] += 1ll * f[i-1][j-1] * (ok[i] - (j-1)) % mod;
                if(f[i][j] >= mod) f[i][j] -= mod;
            }
        }
    }
    int *F = f[n]; 
    for (int i=0; i<=n; ++i) F[i] = 1ll * F[i] * fac[n-i] % mod;
    for (int i=n; i>=0; --i) {
        ans[i] = F[i]; 
        for (int j=i+1; j<=n; ++j) {
            ans[i] -= 1ll * ans[j] * C[j][i] % mod;
            if(ans[i] < 0) ans[i] += mod;
        }
    }
    cout << ans[nWin] << endl; 
    return 0;
}
View Code

 

posted @ 2017-05-28 21:26  Galaxies  阅读(442)  评论(0编辑  收藏  举报