zoukankan      html  css  js  c++  java
  • 【题解】CF#403 D-Beautiful Pairs of Numbers

     这题还挺对胃口的哈哈~是喜欢的画风!回家路上一边听歌一边想到的解法,写出来记录一下……

     首先,由于 (b_{k} < a_{k + 1}) ,所以我们可以看作是在一个长度为 n 的序列上选择出 k 个不相交的区间使得这 k个区间的长度各不相同。那么我们可以先求出 (f[i][j]) 表示选择了 (i) 个区间,这 (i) 个区间的区间长度总和为 (j) 的方案数。然后,我们考虑用这些方案数与序列剩下的长度的划分的方案数共同构成答案。所以我们再求一个 (g[i][j]) 表示将 (j) 的长度划分成可空的 (i) 段的方案数。答案 (h[k][n]) 表示在长为 n 的序列上选出了 (k) 个不相交,各不相同的区间的方案数。有了 (f,g)数组,我们只需要枚举一下选择的区间总长 i,将 (f[k][i] * g[k + 2][n - i]) 加到答案中即可。

      但是,这样做不是 (1000^{3}) 的的吗?实际上,k 的取值范围远不可能到达 1000。由于区间的长度各不相同,我们不难求出当 (k >= 45) 的时候答案为 0,并不需要计算。这样,我们就可以在优秀的 (5e7) 的复杂度下通过此题~

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 1010
    #define maxm 100000
    #define maxk 50
    #define mod 1000000007
    #define int long long
    int N = 1005, lim = 45, h[maxn][maxn];
    int t[2][maxk][maxn], f[maxk][maxn], g[maxk][maxn];
    int fac[maxm], inv[maxm];
    
    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;
    }
    
    int C(int n, int m)
    {
        if(n < m || n < 0 || m < 0) return 0;
        return fac[n] * inv[m] % mod * inv[n - m] % mod;
    }
    
    void pre()
    {
        fac[0] = 1; inv[0] = inv[1] = 1; 
        for(int i = 1; i < maxm; i ++) fac[i] = fac[i - 1] * i % mod;
        for(int i = 2; i < maxm; i ++) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
        for(int i = 2; i < maxm; i ++) inv[i] = inv[i - 1] * inv[i] % mod;
    }
    
    void Up(int &x, int y) { x = x + y; if(x >= mod) x -= mod; }
    void Work()
    {
        int pre = 0, now = 1; t[pre][0][0] = 1;
        for(int i = 1; i <= N; i ++)
        {
            memset(t[now], 0, sizeof(t[now]));
            for(int k = 0; k <= lim; k ++)
                for(int j = 0; j <= N; j ++)
                {
                    t[now][k][j] = t[pre][k][j];
                    if(k && j - i >= 0) Up(t[now][k][j], t[pre][k - 1][j - i]);
                }
            swap(pre, now);
        }
        for(int i = 1; i <= lim; i ++)
            for(int j = 1; j <= N; j ++)
                f[i][j] = t[pre][i][j] * fac[i] % mod;
        for(int i = 0; i <= lim; i ++) g[i][0] = 1;
        for(int i = 1; i <= lim; i ++)
            for(int j = 1; j <= N; j ++)
                g[i][j] = C(i + j - 1, j);
                
        for(int i = 1; i <= lim; i ++)
            for(int j = 1; j < N; j ++)
            {
                int ret = 0;
                for(int k = 1; k <= j; k ++)
                    Up(ret, f[i][k] * g[i + 1][j - k] % mod);
                h[i][j] = ret;
            }
    }
    
    signed main()
    {
        pre(); Work(); int T = read();
        while(T --)
        {
            int n = read(), K = read();
            if(K <= lim) printf("%I64d
    ", h[K][n]);
            else printf("0
    ");
        }
        return 0;
    }
  • 相关阅读:
    Could not get lock /var/lib/apt/lists/lock
    使用vmware提示无法打开内核设备 \.Globalvmx86: 系统找不到指定的文件
    Linux 下安装 MATLAB
    超级干货:Linux常用命令 & 实用命令万字总结!
    GNB 配置图图解
    GNB Linux 部署说明
    解决Firefox启动、打开网页慢、占用内存多
    【Git教程】如何清除git仓库的所有提交记录,成为一个新的干净仓库
    mount --bind和硬连接的区别
    彻底删除 Windows Defender
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9868276.html
Copyright © 2011-2022 走看看