• 51Nod 1327 棋盘游戏


    思路

    打死都不可能想到状态设计DP系列= =

    其实我不会这道题/kk

    以行为状态转移无法记录各列的状态,所以以列为状态转移

    (f[i][j][k])为处理到第(i)列,前面有(j)列没有填棋子,有(k)行已经填到了右区间的方案数

    (l[i],r[i],mid[i])分别为左区间右端点为(i)的行数、右区间左端点为(i)的行数、第(i)列没有被左右区间覆盖的行数

    每次到达左区间右端点的限制(l_{i})时,再考虑如何满足这些左区间,则有如下三种转移:

    • 放在左区间内,就要满足将(l_{i+1})行安排到前面没放棋子的(j)列中,因为顺序没有要求,所以直接乘上排列数,转移为

      [f[i+1][j+1-l_{i+1}][k+r_{i+1}]+=f[i][j][k] imes A_{j+1}^{l_{i+1}} ]

    • 放在右区间内,要乘上左右两侧的方案数

      [f[i+1][j-l_{i+1}][k+r_{i+1}-1]+=f[i][j][k] imes A_{j}^{l_{i+1}} imes (k+r_{i+1}) ]

    • 放在未被覆盖的中间位置,要乘上左侧和中间的方案数

      [f[i+1][j-l_{i+1}][k+r_{i+1}]+=f[i][j][k] imes mid_{i+1} imes A_{j}^{l_{i+1}} ]

    初始状态为(f[0][0][0]=1),最后的答案为(sum_{i=1}^{m}f[m][i][0])

    代码

    /*
    Author:loceaner
    */
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define int long long
    using namespace std;
    
    const int A = 211;
    const int B = 61;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
        char c = getchar();
        int x = 0, f = 1;
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
        for (; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
        return x * f;
    }
    
    int n, m, ans, l[A], r[A], mid[A], c[A][A], fac[A], f[A][A][B];
    
    signed main() {
        n = read(), m = read();
        for (int i = 1; i <= n; i++) {
            int L = read(), R = read();
            l[L]++, r[m - R + 1]++, mid[L + 1]++, mid[m - R + 1]--;
        }
        for (int i = 1; i <= m; i++) mid[i] += mid[i - 1];
        c[0][0] = 1, fac[0] = 1, f[0][0][0] = 1;
        for (int i = 1; i <= m; i++) {
            c[i][0] = c[i][i] = 1, fac[i] = fac[i - 1] * i % mod;
            for (int j = 1; j < i; j++) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
        }
        for (int i = 0; i < m; i++)
            for (int j = 0; j <= i; j++)
                for (int k = 0; k <= n; k++)
                    if (f[i][j][k]) {
                        if (j + 1 >= l[i + 1])  //放在左区间
                            (f[i + 1][j + 1 - l[i + 1]][k + r[i + 1]] += f[i][j][k] * (c[j + 1][l[i + 1]] * fac[l[i + 1]] % mod) % mod) %= mod;
                        if (j >= l[i + 1])  //放在中间
                            (f[i + 1][j - l[i + 1]][k + r[i + 1]] += f[i][j][k] * (c[j][l[i + 1]] * fac[l[i + 1]] % mod) % mod * mid[i + 1] % mod) %= mod;
                        if (j >= l[i + 1] && k + r[i + 1])  //放在右区间
                            (f[i + 1][j - l[i + 1]][k + r[i + 1] - 1] += f[i][j][k] * (c[j][l[i + 1]] * fac[l[i + 1]] % mod) % mod * (k + r[i + 1]) % mod) %= mod;
                    }
        for (int i = 0; i <= m; i++) ans = (ans + f[m][i][0]) % mod;
        cout << ans << '
    ';
        return 0;
    }
    
  • 相关阅读:
    Kingbase数据库中查询锁表以及解锁
    数据库事务隔离级别
    DB2数据库报错:com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=204, SQLSTATE=42704, SQLERRMC=DB2INSTL.USER, DRIVER=4.19.80
    MySQL数据库中查询锁表以及解锁
    Maven 项目报错SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder"
    uniapp微信小程序自动检测更新
    uniapp云开发实现微信小程序实现login并记录用户信息
    【转载】Eclipse完善代码自动补全功能(很好用)
    【杂项】+IT培训机构名录
    【Java】json排序/根据key排序/不限层级/字母排序
  • 原文地址:https://www.cnblogs.com/loceaner/p/13239320.html
Copyright © 2020-2023  润新知