zoukankan      html  css  js  c++  java
  • [BZOJ3622] 已经没有什么好害怕的了(dp+容斥)

    Description:

    ​ 有两个数组a和b,两两配对,求 (a_i>b_i) 的配对比 (b_i>a_i) 的配对多 (k) 个的方案数

    (kle nle 2000)

    Solution:

    ​ 先将 (a,b) 排序,求出 (cnt[i]) 表示比 (a[i]) 小的 (b[j]) 有多少个,然后恰好k个不好求,求至少 (k) 个,然后容斥。

    ​ 设 (dp[i][j]) 表示到 (a) 的前 (i) 位,有 (j)(a>b)

    [dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] imes(cnt[i] - j + 1) ]

    ​ 然后随便容斥一下就好了,不要忘了乘组合数。

    [Ans = sum_{i=k}^n(-1)^{i-k}{~i~ choose k}dp[n][i](n-i)! ]

    Code

    #include <vector>
    #include <cmath>
    #include <cstdio>
    #include <cassert>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    typedef long long LL;
    typedef unsigned long long uLL;
    
    #define fir first
    #define sec second
    #define SZ(x) (int)x.size()
    #define MP(x, y) std::make_pair(x, y)
    #define PB(x) push_back(x)
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    #define GO debug("GO
    ")
    #define rep(i, a, b) for (register int i = (a), i##end = (b); (i) <= i##end; ++ (i))
    #define drep(i, a, b) for (register int i = (a), i##end = (b); (i) >= i##end; -- (i))
    #define REP(i, a, b) for (register int i = (a), i##end = (b); (i) < i##end; ++ (i))
    
    inline int read() {
        register int x = 0; register int f = 1; register char c;
        while (!isdigit(c = getchar())) if (c == '-') f = -1;
        while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));
        return x * f;
    }
    template<class T> inline void write(T x) {
        static char stk[30]; static int top = 0;
        if (x < 0) { x = -x, putchar('-'); }
        while (stk[++top] = x % 10 xor 48, x /= 10, x);
        while (putchar(stk[top--]), top);
    }
    template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
    template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
    
    using namespace std;
    
    const int maxN = 2003;
    const int MOD = 1e9 + 9;
    
    int n, k, ans;
    int C[maxN][maxN], dp[maxN][maxN], a[maxN], b[maxN], cnt[maxN], fac[maxN];
    
    void pls(int &x, int y)
    {
        x += y;
        if (x >= MOD) x -= MOD;
        if (x < 0) x += MOD;
    }
    
    void init()
    {
        C[0][0] = 1;
        for (int i = 1; i <= n; ++i)
        {
            C[i][0] = C[i][i] = 1;
            for (int j = 1; j < i; ++j)
                pls(C[i][j], C[i - 1][j]), pls(C[i][j], C[i - 1][j - 1]);
        }
    }
    
    int main() 
    {
    #ifndef ONLINE_JUDGE
        freopen("xhc.in", "r", stdin);
        freopen("xhc.out", "w", stdout);
    #endif
        cin >> n >> k;
        if ((n + k) & 1) 
        {
            puts("0");
            return 0;
        }
        k = (n + k) >> 1;
        for (int i = 1; i <= n; ++i)
            cin >> a[i];
        for (int i = 1; i <= n; ++i)
            cin >> b[i];
        sort(a + 1, a + 1 + n);
        sort(b + 1, b + 1 + n);
    
        init();
        
        fac[0] = 1;
        for (int i = 1; i <= n; ++i) fac[i] = 1ll * fac[i - 1] * i % MOD;
        for (int i = 1; i <= n; ++i)
        {
            cnt[i] = cnt[i - 1];
            while (a[i] > b[cnt[i]] and cnt[i] <= n)
                cnt[i]++;
            cnt[i]--;
        }
    
        dp[0][0] = 1;
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 0; j <= cnt[i]; ++j)
            {
                pls(dp[i][j], dp[i - 1][j]);
                if (j)
                    pls(dp[i][j], 1ll * dp[i - 1][j - 1] * max(cnt[i] - j + 1, 0) % MOD);
            }
        }
    
        for (int i = k; i <= n; ++i)
        {
            if ((i - k) & 1)
                pls(ans, -1ll * dp[n][i] * fac[n - i] % MOD * C[i][k] % MOD);
            else
                pls(ans, 1ll * dp[n][i] * fac[n - i] % MOD * C[i][k] % MOD);
        }
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    java基础教程-流IO(五)
    java基础教程-常用类(四)
    java基础教程-容器(三)
    java基础教程-异常处理(二)
    java基础教程-面向对象(一)
    javascript DOM编程艺术(笔记)
    二十二、动态规划
    二十一、所有结点对最短路径问题(弗洛伊德算法)
    二十、单源最短路径(迪杰斯特拉算法)
    十九、最小生成树(普里姆算法)
  • 原文地址:https://www.cnblogs.com/cnyali-Tea/p/11439897.html
Copyright © 2011-2022 走看看