zoukankan      html  css  js  c++  java
  • 【题解】51nod 1327 棋盘游戏

    原题链接

    51nod 1327 棋盘游戏

    题意

    • 给定一个 (n imes 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] imes A_{j + 1}^{l[i + 1]} ]

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

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

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

    然后最后答案就是 $$sumlimits_{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
    ", ans); 
        return 0;
    }
    
  • 相关阅读:
    this指向
    作用域链
    入门
    一、servlet之初见
    jdbc之mysql
    第六章、树和二叉树
    第七章、暴力求解法
    机试
    第十三章、字符串
    栈和队列
  • 原文地址:https://www.cnblogs.com/eqvpkbz/p/14063871.html
Copyright © 2011-2022 走看看