zoukankan      html  css  js  c++  java
  • [BZOJ 3622]已经没有什么好害怕的了

    Description

    题库链接

    给出 (n) 个数 (a_i) ,以及 (n) 个数 (b_i) ,要求两两配对使得 (a>b) 的对数减去 (a<b) 的对数等于 (k)

    (0leq kleq nleq 2000) ,保证 (a,b) 无相同元素。

    Solution

    我们假设 (a>b) 对数为 (x) ,可以求得 (x=frac{n+k}{2})

    我们令 (f_{i,j}) 表示前 (i)(a) 中,选了 (j) 组满足 (a>b) 的方案数。

    容易得到 ( ext{dp}) 方程

    [f_{i,j}=f_{i-1,j}+(l_i-j+1) imes f_{i-1,j-1}]

    其中 (l_i) 表示从小到大排序后 (b)(<a_i) 的最靠后一个数。

    我们记 (g_i=f_{n,i} imes (n-i)!) 即满足 (a>b) 的组数 (geq i) 的方案数,再令 (f_i) 表示恰好满足 (a>b) 的组数 (= i) 的方案数。

    容易发现对于 (i>j) (f_i) 恰好在 (g_j) 中算了 ({ichoose j}) 次。

    那么存在

    [g(k)=sum_{i=k}^n{ichoose k}f(i)]

    由二项式反演得

    [f(k)=sum_{i=k}^n(-1)^{i-k}{ichoose k}g(i)]

    直接求解即可。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2000+5, yzh = 1e9+9;
    
    int n, k, a[N], b[N], l[N], f[N][N], fac[N], ifac[N], g[N];
    
    int C(int n, int m) {return 1ll*fac[n]*ifac[m]%yzh*ifac[n-m]%yzh; }
    void work() {
        scanf("%d%d", &n, &k);
        if ((n+k)&1) {puts("0"); return; } k = (n+k)/2;
        ifac[0] = ifac[1] = fac[0] = fac[1] = 1;
        for (int i = 2; i < N; i++) ifac[i] = -1ll*yzh/i*ifac[yzh%i]%yzh;
        for (int i = 2; i < N; i++)
            fac[i] = 1ll*fac[i-1]*i%yzh, ifac[i] = 1ll*ifac[i-1]*ifac[i]%yzh;
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &b[i]);
        sort(a+1, a+n+1); sort(b+1, b+n+1);
        int loc = 0;
        for (int i = 1; i <= n; i++) {
            while (loc < n && b[loc+1] < a[i]) ++loc;
            l[i] = loc;
        }
        f[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            f[i][0] = f[i-1][0];
            for (int j = 1; j <= i; j++)
                f[i][j] = (1ll*f[i-1][j]+1ll*f[i-1][j-1]*max(0, l[i]-j+1)%yzh)%yzh;
        }
        for (int i = 0; i <= n; i++) g[i] = 1ll*f[n][i]*fac[n-i]%yzh;
        int ans = 0;
        for (int i = k; i <= n; i++)
            if ((i-k)&1) (ans -= 1ll*C(i, k)*g[i]%yzh) %= yzh;
            else (ans += 1ll*C(i, k)*g[i]%yzh) %= yzh;
        printf("%d
    ", (ans+yzh)%yzh);
    }
    int main() {work(); return 0; }
  • 相关阅读:
    委托 你怎么看?
    读懂IL代码就这么简单(二)
    读懂IL代码就这么简单 (一)
    C#操作XML方法集合
    文件夹管理工具(MVC+zTree+layer)(附源码)
    操作文件方法简单总结(File,Directory,StreamReader,StreamWrite )
    让你彻底理解 “==”与 Equals
    处理 EF 并发其实就这么简单
    CentOs7.5安装PostgreSQL11
    SQLAlchemy+Flask-RESTful使用(四)
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/9245071.html
Copyright © 2011-2022 走看看