【題解】已經沒有什麼好懼怕的了

  套路滿滿的樣子(o°ω°o) 實際上在發現‘比...多 \(K\) 實際上就是要求糖果能量大於藥片能量的組數爲 \(K'\) 時,這題的指向性就很明確了。按照慣例來講,咱們應當試圖用‘至少’來求出‘剛好’的方案數。c++

  先考慮容斥的部分:若是能夠求出每個糖果集合 \(T\) 使得 \(T\) 中的全部糖果在最後的組合方案中能量都可以大於所匹配的藥片的能量的方案數 \(h_{i}\),那麼令spa

\(ans = \sum_{T\subseteq S}^{\ }f_{t}*h_{t}\)code

因爲只要剛好爲 \(K\) 的方案數blog

因此一個‘糖果大於藥片’組數爲 \(T\) 的方案應對答案產生貢獻爲:排序

\(g_{x}=\sum_{i = 0}^{x}f_{i}*\binom{x}{i}=[x = K]\)get

二項式反演,便可得:it

\(f_{x}=\sum_{i = 0}^{x}(-1)^{x - K}*\binom{x}{K}\)class

  解決了容斥係數,再考慮如何求出至少 \(i\) 組中糖果能量大於藥片能量的方案數?因爲題目容許 \(n^{2}\) 的複雜度,不妨大膽設dp狀態 \(dp[i][j]\) 表示將糖果與藥片均從小到大排序後,糖果組合到第 \(i\) 個,已經有 \(j\) 組糖果 > 藥片的方案數。考慮當前糖果是組合一個比本身大的仍是暫不考慮便可。最後求得的方案數中,雖然保證了有 \(x\) 組糖果 > 藥片,但並無對剩下的元素提出要求。因此都乘上一個 \(fac[n - x]\) 即爲所求。sort

  完美解決ヾ(o´∀`o)ノ集合

#include <bits/stdc++.h>
using namespace std;
#define maxn 3005
#define CNST 3000
#define mod 1000000009
int n, K, ans, C[maxn][maxn], f[maxn][maxn];
int fac[maxn], g[maxn], rec[maxn], a[maxn], b[maxn];

int read()
{
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

void Up(int &x, int y) { x = (x + y) % mod; }
void Pre()
{
    fac[0] = 1; for(int i = 1; i < maxn; i ++) fac[i] = 1ll * fac[i - 1] * i % mod;
    for(int i = 0; i < CNST; i ++) C[i][0] = 1;
    for(int i = 1; i < CNST; i ++)
        for(int j = 1; j < CNST; j ++)
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod; 
}

void DP()
{
    f[0][0] = 1;
    for(int i = 0; i <= n; i ++)
        for(int j = 0; j <= i; j ++)
        {
            int t = i + 1;
            Up(f[t][j], f[i][j]);
            if(rec[t] > j) Up(f[t][j + 1], 1ll * f[i][j] * (rec[t] - j) % mod);
        }
    for(int i = 1; i <= n; i ++) f[n][i] = 1ll * f[n][i] * fac[n - i] % mod;
}

void In_ex()
{
    for(int i = K; i <= n; i ++)
        g[i] = 1ll * (((i - K) & 1) ? -1 : 1) * C[i][K] % mod;
    for(int i = K; i <= n; i ++) 
        Up(ans, 1ll * g[i] * f[n][i] % mod);
}

int main()
{
    n = read(), K = read(); Pre(); 
    if(n + K & 1) { printf("0\n"); }
    else K = (n + K) >> 1;
    for(int i = 1; i <= n; i ++) a[i] = read();
    for(int i = 1; i <= n; i ++) b[i] = read();
    sort(a + 1, a + 1 + n);
    sort(b + 1, b + 1 + n);
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
            if(b[j] > a[i]) { rec[i] = j - 1; break; }
            else if(j == n) rec[i] = n;
    DP(); In_ex();
    printf("%d\n", (ans + mod) % mod);
    return 0;
}
相關文章
相關標籤/搜索