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;
}

浙公网安备 33010602011771号