【题解】51nod 1327 棋盘游戏

原题链接

51nod 1327 棋盘游戏

题意

  • 给定一个 \(n \times m\) 的棋盘
  • 给定每行一个左区间 \([1, L[i]]\) 和一个右区间 \([m - R[i] + 1, m]\)
  • 每列有且仅能有一颗棋子, 每个左区间有且仅有一颗棋子, 右区间有且仅有一颗棋子
  • 保证每一行的左右区间不相交

求合法方案数

解题报告

这题挺妙的, 虽然可能妙得不是非常直观

首先, 因为考虑每一列只能填一个, 考虑怎么填

声明 \(l[i]\) 为以 \(i\) 为左区间右端点的行数, \(r[i]\) 为以 \(i\) 为右区间左端点的行数, \(mid[i]\) 为第 \(i\) 列上有多少没有被左右区间覆盖的行数

于是可以设计一个状态 \(f[i][j][k]\) 表示当前考虑到了第 \(i\) 列, 有 \(j\) 列没填, \(k\) 行左端点 \(\le i\) 的右区间没有填任何棋子的方案数

则能够考虑第 \(i + 1\) 列的棋子填在哪里, 而且每次让左区间强行满足条件, 即左区间右端点 \(\le i\) 的每一个左区间都有且仅有一颗棋子

有:

\(i + 1\) 列的棋子被左区间覆盖:

\[f[i + 1][j - l[i + 1] + 1][k + r[i + 1]] += f[i][j][k] \times A_{j + 1}^{l[i + 1]} \]

\(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]) \]

\(i + 1\) 列的棋子没有被左区间或右区间覆盖:

\[f[i + 1][j - l[i + 1]][k + r[i + 1]] += f[i][j][k] \times A_{j}^{l[i + 1]} \times (mid[i + 1]) \]

然后最后答案就是 $$\sum\limits_{i = 0}^{m} f[m][i][0]$$

代码实现

Sample Code
#include <cstdio>

#define re register
#define rep(i, a, b) for(re int i = (a); i <= (b); ++ i)
#define Rep(i, a, b) for(re int i = (a); i <  (b); ++ i)

typedef long long ll;
const ll mod = 1e9 + 7;
const ll N = 2e2 + 5;

int n, m, l, r; 
ll MID[N], L[N], R[N];
ll ans, f[N][N][N];
ll fac[N], P[N][N];

void add(ll &x, ll y) { x = (x + y) % mod; }

int main() {
	scanf("%d%d", &n, &m); 
	rep(i, 1, n) {
		scanf("%d%d", &l, &r); 
		rep(j, l + 1, m - r) 
			MID[j] ++;
        L[l] ++, R[m - r + 1] ++;
    }
	
	rep(i, 0, m) P[i][0] = 1;
	rep(i, 1, m) rep(j, 1, i) 
        P[i][j] = (P[i - 1][j - 1] + P[i - 1][j]) % mod;
    fac[0] = 1;
	rep(i, 1, m) fac[i] = fac[i - 1] * i % mod;
    rep(i, 1, m) rep(j, 1, i) 
        P[i][j] = P[i][j] * fac[j] % mod;
    
	f[0][0][0] = 1;
	Rep(i, 0, m) rep(j, 0, i) rep(k, 0, n) {
		if (!f[i][j][k]) continue;
		if (j + 1 >= L[i + 1]) {
			ll tmp = f[i][j][k] * P[j + 1][L[i + 1]] % mod;
			add(f[i + 1][j + 1 - L[i + 1]][k + R[i + 1]], tmp);
		}
		if(j >= L[i + 1]) {
			ll tmp = f[i][j][k] * MID[i + 1] % mod * P[j][L[i + 1]] % mod;
			add(f[i + 1][j - L[i + 1]][k + R[i + 1]], tmp);
			if(k + R[i + 1]) {
				tmp = f[i][j][k] * (k + R[i + 1]) % mod * P[j][L[i + 1]] % mod;
				add(f[i + 1][j - L[i + 1]][k + R[i + 1] - 1], tmp);
			}
		}
	} rep(i, 0, m) add(ans, f[m][i][0]);
    printf("%lld\n", ans); 
    return 0;
}
posted @ 2020-11-30 21:26  Eqvpkbz  阅读(129)  评论(0编辑  收藏  举报