标签:
一道区间DP题,某次BestCoder的B题,想了很久没想出来。
题目描述:一共有并排N个椅子, N个学生依次去坐,同时满足3个条件就不能坐下去:1,该椅子不在最左,不在最右,2,该椅子左右都有人坐了,3,左右的椅子不同颜色
求最后N个人都能坐下去,有多少不同的情况.
题解:dp[i][j]表示排完区间[i,j]的种类数,(看别人题解时没想明白,人是按顺序先后决定坐的位置,即在区间[i,j]内座位的先后序。当[i,j]->[1,n]时,dp的种类数不就是n个人按顺序先后决定坐的位置的种类)
转移方程: dp[i][j] = SUM ( dp[i][k-1]*dp[k+1][j]* C[j-i][i-k] ) 其中v[k-1]==v[k+1],保证最后的那个最为合法。乘以组合数的原因是在j-i个人中决定坐前一个区间的人(选完之后,他们是有序的)。
代码君:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> const int N = 100+10; const int mod = 1e9+7; typedef long long ll; ll dp[N][N]; int a[N]; ll C[N][N]; void init() { for(int i=0;i<=100;i++) C[i][0] = 1; for(int i=1;i<=100;i++) for(int j=1;j<=i;j++) C[i][j] =( C[i-1][j-1] + C[i-1][j] )%mod; } ll dfs(int i,int j) { if(i>j) return 0; if(i==j) return dp[i][j]=1; if(dp[i][j]!=-1) return dp[i][j]; ll ans = 0; ans =( dfs(i+1,j) + dfs(i,j-1) )%mod; for(int k=i+1;k<=j-1;k++) { if(a[k-1]!=a[k+1]) continue; ans = ( ans + dfs(i,k-1)*dfs(k+1,j)%mod*C[j-i][k-i]%mod)%mod; } return dp[i][j] = ans; } int main() { int n; init(); while(scanf("%d",&n)!=EOF) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); memset(dp,-1,sizeof(dp)); ll ans = dfs(1,n); printf("%lld\n",ans); } return 0; }
标签:
原文地址:http://blog.csdn.net/alpc_wt/article/details/42291361