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]\times A_{j+1}^{l_{i+1}} \] -
放在右区间内,要乘上左右两侧的方案数
\[f[i+1][j-l_{i+1}][k+r_{i+1}-1]+=f[i][j][k]\times A_{j}^{l_{i+1}}\times (k+r_{i+1}) \] -
放在未被覆盖的中间位置,要乘上左侧和中间的方案数
\[f[i+1][j-l_{i+1}][k+r_{i+1}]+=f[i][j][k]\times mid_{i+1}\times 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 << '\n';
return 0;
}
转载不必联系作者,但请声明出处