【题解】51nod1327 棋盘游戏

  那天和机房的同学们一起想了很久,然而并没有做出来……今天看了题解,的确比较巧妙,不过细细想来其实规律还是比较明显,在这里记录一下~

  当天自己做的时候,主要想到的是两点 : 1.按列dp 2.对行进行排序。虽然没有做出来,但做法的确和这两点是重合的。我们考虑强制满足左端点,然后 dp 右端点的方法,记录状态 (f[i][j][k]) 为 dp 到第 (i) 列时,有 (j) 列是空的,且还有 (k) 个右端点没有满足(这 (k) 个右端点的位置均 (<= i))。

  首先从 (i) 转移到 (i + 1) 的条件就是 (j + 1 >= b[i + 1]) 其中 b 数组存的是以 (x) 为左端点的行数。这样做的本质就是将行按照左端点从小到大排序之后依次满足,端点为 (x) 的就强制在转移到第 (x) 列的时候去进行考虑(一方面一定要满足,另一方面可以放的范围已经限制了)。转移的时候我们分成三种情况:强制第 (i) 列不放 / 放一个满足左端点,满足一个右端点和放在一个空白的位置。对于后面两种转移,只有当 (j >= b[i + 1]) 时才会发生(说明我们可以选择将多出来的这一行去用于满足右端点 、放在空白)。这样就只需要讨论一下满足的是哪一个右端点和空白,对于一起转移的满足的左端点乘上排列数以统计不同的方案就可以了。

  很棒的题,奈何自己太弱啦……加油ヾ(◍°∇°◍)ノ゙

#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define maxn 205
#define int long long
int n, m, a[maxn], b[maxn], c[maxn];
int ans, f[maxn][maxn][maxn];
int fac[maxn], P[maxn][maxn];

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;
}

void pre()
{
    for(int i = 0; i <= m; i ++) P[i][0] = 1;
    for(int i = 1; i <= m; i ++)
        for(int j = 1; j <= i; j ++) 
            P[i][j] = (P[i - 1][j - 1] + P[i - 1][j]) % mod;
    fac[0] = 1;
    for(int i = 1; i <= m; i ++) fac[i] = fac[i - 1] * i % mod;
    for(int i = 1; i <= m; i ++)
        for(int j = 1; j <= i; j ++)
            P[i][j] = P[i][j] * fac[j] % mod;
}

void Up(int &x, int y) { x = (x + y) % mod; }

void DP()
{
    f[0][0][0] = 1;
    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]) continue;
                if(j + 1 >= b[i + 1])
                {
                    int tem = f[i][j][k] * P[j + 1][b[i + 1]] % mod;
                    Up(f[i + 1][j + 1 - b[i + 1]][k + c[i + 1]], tem);
                }
                if(j >= b[i + 1])
                {
                    int tem = f[i][j][k] * a[i + 1] % mod * P[j][b[i + 1]] % mod;
                    Up(f[i + 1][j - b[i + 1]][k + c[i + 1]], tem);
                    if(k + c[i + 1])
                    {
                        tem = f[i][j][k] * (k + c[i + 1]) % mod * P[j][b[i + 1]] % mod;
                        Up(f[i + 1][j - b[i + 1]][k + c[i + 1] - 1], tem);
                    }
                }
            }
}

signed main()
{
    n = read(), m = read();
    for(int i = 1; i <= n; i ++)
    {
        int l = read(), r = read();
        for(int j = l + 1; j <= m - r; j ++) a[j] ++;
        b[l] ++, c[m - r + 1] ++;
    }
    pre(); DP();
    for(int i = 0; i <= m; i ++) Up(ans, f[m][i][0]);
    printf("%lld
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/twilight-sx/p/9571701.html