• 2016北京集训测试赛(十七)Problem A: crash的游戏


    Description

    Solution

    相当于要你计算这样一个式子:

    [sum_{x = 0}^m left( egin{array}{} m \ x end{array} ight) left( egin{array}{} k \ n - m + 2x end{array}{} ight) ]

    考虑到(m)非常大, 而(k)却比较小, 我们尝试将(x)(m)相关转化为(k)相关. 我们用如下现实意义来考虑: 令(N = n - m), 则我们相当于有两堆球, 第一堆球以单个球为单位, 总共(N)个, 我们要在其中取出(i)个; 第二堆球以一对球连在一起为单位, 总共有(m)对, 我们要在其中取出任意多对球, 拆开放入第一堆中, 然后问你在第一堆中取(k)个球总共有多少种的方案.
    这个问题仍然不好解决, 我们继续考虑: 我们假设这(k)个球中, 总共用了第二堆球中的(j)对. 也就是说, 这(k)个球中(i)个是在第一堆中取来的, 剩下(k - i)个用到了第二堆中的(j)对球, 其中每一对既有可能被用了一个, 也有可能用了两个. 考虑方案数: 在第一堆中取(i)个显然就是(left( egin{array}{} N \ i end{array}{} ight)); 我们用f[i][j]来表示在第2堆中用到(i)对, 并且总共取出(j)个球的方案数, 考虑(f[i][j])的递归式:

    [f[i][j] = f[i - 1][j - 1] imes 2 + f[i - 1][j - 2] ]

    这样以来, 总共的方案数就是

    [sum_i sum_j left( egin{array}{} N \ i end{array}{} ight) f[i][N - k] ]

    考虑到询问有(500)组, 我们要作一些预处理, 记忆化某些信息.

     
    #include <cstdio>
    #include <cctype>
     
    namespace Zeonfai
    {
        inline int getInt()
        {
            int a = 0, sgn = 1; char c;
            while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
            while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
            return a * sgn;
        }
    }
    const int K = 300, MOD = (int)1e9 + 7;
    int prod[K + 1], prodInv[K + 1], f[K + 1][K << 2], dwn[K + 1], _dwn[K + 1], pw[K + 1];
    inline int power(int a, int x)
    {
        if(x < 0) return 0;
        int res = 1;
        for(; x; a = (long long)a * a % MOD, x >>= 1) if(x & 1) res = (long long)res * a % MOD;
        return res;
    }
    inline int _C(int m)
    {
        if(m < 0) return 0;
        return (long long)_dwn[m] * prodInv[m] % MOD;
    }
    inline int C(int m)
    {
        if(m < 0) return 0;
        return (long long)dwn[m] * prodInv[m] % MOD;
    }
    inline void pretreat()
    {
        prod[0] = prodInv[0] = 1; for(int i = 1; i <= K; ++ i) prod[i] = (long long)prod[i - 1] * i % MOD, prodInv[i] = power(prod[i], MOD - 2);
        f[0][0] = 1;
        for(int i = 1; i <= K; ++ i) for(int j = 1; j <= i << 1; ++ j) f[i][j] = (f[i - 1][j - 1] * 2 % MOD + (j >= 2 ? f[i - 1][j - 2] : 0)) % MOD;
    }
    int main()
    {
     
        #ifndef ONLINE_JUDGE
     
        freopen("crash.in", "r", stdin);
        freopen("crash.out", "w", stdout);
     
        #endif
     
        using namespace Zeonfai;
        pretreat();
        for(int T = getInt(); T --; )
        {
            int n = getInt(), m = getInt(), k = getInt(), ans = 0;
            dwn[0] = 1; dwn[1] = m; for(int i = 2; i <= k; ++ i) dwn[i] = (long long)dwn[i - 1] * (m - i + 1) % MOD;
            _dwn[0] = 1; _dwn[1] = n - m; for(int i = 2; i <= k; ++ i) _dwn[i] = (long long)_dwn[i - 1] * (n - m - i + 1) % MOD;
            for(int i = 0; i <= k; ++ i) pw[i] = power(2, m - i);
            for(int i = 0; i <= k; ++ i)
            {
                int cur = 0;
                for(int j = (k - i + 1) / 2; j <= k - i; ++ j)
                    cur = (cur + (long long)C(j) % MOD * pw[j] % MOD * f[j][k - i] % MOD) % MOD;
                ans = (ans + (long long)cur * _C(i) % MOD) % MOD;
            }
            printf("%d
    ", ans);
        }
    }
    
  • 相关阅读:
    摆花
    关于我的博客
    博客美化更新日志
    页面美化代码1.x
    本人已转至新博客!
    回归博客园
    退役快乐
    Luogu神贴合辑
    代码高亮预览
    NOIp2018普及组初赛解题报告
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7464873.html
Copyright © 2020-2023  润新知