[51nod 1327] 棋盘游戏

有一个N行M列的棋盘,即该棋盘被分为N*M格。现在向棋盘中放棋子,每个格子中最多放一个棋子,也可以一个不放。放完棋子后需要满足如下要求:
1)对于第i行来说,其从左往右的前left[i] 个格子(即最左侧的left[i] 个连续的格子)中恰好一共有1个棋子;
2)对于第i行来说,其从右往左的前right[i]个格子(即最右侧的right[i]个连续的格子)中恰好一共有1个棋子;
3)对于每一列来说,这一列上的所有格子内含有的棋子数不得超过1个。
其中,1)与2)条件中,对所有 i 满足 left[i]+right[i] <= M,即两个区间不会相交。
问,符合上述条件情况下棋子的不同放法一共有多少种?输出放法的个数 mod  1,000,000,007后的结果。
 
例如样例中,只有如下图一种方法。
           
Input
第一行包含两个整数,N,M,其中1<=N<=50,2<=M<=200.
之后有N行,每行两个数left[i],right[i],其中,1<=left[i],right[i]<=M,且 left[i]+right[i] <= M。
Output
一个整数,即符合条件的方案数mod 1,000,000,007后的结果。
Input示例
2 4
1 2
2 1
Output示例
1




打死都想不出系列。

 


 

 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
inline int read() {
    int res = 0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48), ch=getchar();
    return res;
}
#define reg register
#define mod 1000000007
#define ll long long
#define int long long
int n, m;
int L[205], R[205], Mid[205];
int f[205][205][55];
int fac[205], C[205][205];

inline int ksm(int x, int y)
{
    int res = 1;
    while(y)
    {
        if (y & 1) res = (ll)(res * x) % mod;
        x = (ll)(x * x) % mod;
        y >>= 1; 
    }
    return res;
}
ll ans;
signed main()
{
    n = read(), m = read();
    for (reg int i = 1 ; i <= n ; i ++)
    {
        int l = read(), r = read();
        L[l] ++, R[m+1-r]++;
        for (reg int j = l + 1 ; j <= m - r ; j ++)    Mid[j]++;
    }
    fac[0] = 1;
    for (reg int i = 1 ; i <= 200 ; i ++)
        fac[i] = fac[i-1] * i % mod;
    C[0][0] = 1;
    for (reg int i = 1 ; i <= 200 ; i ++)
    {
        C[i][0] = 1;
        for (reg int j = 1 ; j <= i ; j ++)
            C[i][j] = (C[i-1][j] + C[i-1][j-1]) % mod;
    }
    f[0][0][0] = 1;
    for (reg int i = 0 ; i < m ; i ++)
        for (reg int j = 0 ; j <= i ; j ++)
            for (reg int k = 0 ; k <= n ; 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]] * Mid[i+1]) % mod) % mod) %= mod; //放在中间的空行 
                    if (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 * (k + R[i+1])) % mod) % mod) %= mod;
                }
            }
    for (reg int i = 0 ; i <= m ; i ++)
        ans = (ans + f[m][i][0]) % mod;
    printf("%lld\n", ans);
    return 0;
}

 

posted @ 2018-08-28 16:58  zZhBr  阅读(322)  评论(0编辑  收藏  举报