HDU5151 Sit sit sit(区间 dp+组合数学)

目录

Description

\(n\) 个座位,每个座位都有相应的颜色,当 \(x\) 想要坐下时,如果座位 \(i\) 满足以下三个条件

1.座位 \(i\) 并不位于 \(1\) 号和 \(n\)

2.座位 \(i-1\)\(i+1\) 都已经有人

3.座位 \(i-1\)\(i+1\) 的颜色不同

那么 \(x\) 将不坐在 \(i\)

求将 \(n\) 个座位全部坐满有多少种情况

State

\(1<=n<=100\)

\(0<=a[i]<=1\)

Input

3
1 0 0
4
1 0 0 1

Output

4
8

Solution

\(dp[i][j]\)\([i,j]\) 区间全部坐满学生的总情况数,其中每一个位置都有可能成为最后一个座位,将其设为 \(k\)

如果 \(a[k-1]!=a[k+1]\),那么 \(dp[i][k-1]\)\(dp[k+1][j]\) 是可以合并的,到此,合并起来 \(dp[i][j]\) 是多少呢?

\(n\) 个座位全部坐满的理想情况是 \(n!\)\(m\) 个座位全部坐满的理想情况是 \(m!\),将这些座位合并答案为 \((n+m)!=n!*m!*C_{n+m}^n\),如果不是理想状况也同样满足 (大雾)

\(hint:\) 注意 \(k\) 作为 \([i,j]\) 端点的情况


Code

#define ADD(a, b) a = ((a + b) % mod + mod) % mod
const int mod = 1e9 + 7;
const int N = 100 + 5;
 
    int n, m, k, _;
    int a[N];
    ll dp[N][N];
    ll C[N][N]; 

void init()
{
    for(int i = 0; i <= 100; i ++){
        C[i][0] = C[i][i] = 1;
        for(int j = 1; j < i; j ++){
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
        }
    }
}

signed main()
{
    // IOS;
    init();
    while(~ sd(n)){
        rep(i, 1, n) sd(a[i]);
        ms(dp, 0);
        for(int i = 1; i <= n; i ++) dp[i][i] = 1;
        for(int len = 2; len <= n; len ++){
            for(int i = 1; i <= n; i ++){
                int j = i + len - 1;
                if(j > n) break;
                ADD(dp[i][j], dp[i + 1][j]);
                ADD(dp[i][j], dp[i][j - 1]);
                for(int k = i + 1; k <= j - 1; k ++){
                    if(a[k + 1] == a[k - 1]){
                        ADD(dp[i][j], dp[i][k - 1] * dp[k + 1][j] % mod * C[j - i][k - i] % mod);
                    }
                }
            }
        }
        pll(dp[1][n]);
    }
    // PAUSE;
    return 0;
}
posted @ 2021-10-08 18:13  Bcoi  阅读(53)  评论(0)    收藏  举报