【问题描述】
有一个长度为n的括号序列,以及k种不同的括号。序列的每个位置上是哪种括号是随机的,并且已知每个位置上出现每种左右括号的概率。求整个序列是一个合法的括号序列的概率。
我们如下定义合法括号序列:
空序列是合法括号序列;
如果A合法括号序列,那么lAr是合法括号序列,当且仅当l和r是同种的左右括号;
如果A和B是合法括号序列,那么AB是合法括号序列。
【输入格式】
输入第一行包含两个整数n和k。接下来的输入分为?组,每组?行。第?组第
?行包含两个实数?[?,?]和?[?,?],分别代表第?个位置上是第?类的左括号和右括号
的概率。
【输出格式】
输出一行,包含一个实数,代表序列是合法括号序列的概率。建议保留至少
5 位小数输出。只有当你的输出与标准答案之间的绝对误差不超过10 −5 时,才会
被判为正确。
【样例输入 1】
2 1
1.00000 0.00000
0.00000 1.00000
【样例输出 1】
1.00000
【样例输入 2】
4 1
0.50000 0.50000
1.00000 0.00000
0.00000 1.00000
0.50000 0.50000
【样例输出 2】
0.25000
【数据规模和约定】
对于20%的数据,? ≤ 50,? = 1,所有位置的概率非 0 即 1。
另外有 30%的数据,? ≤34,? = 1,前 10 个和后 10 个位置的所有概率都是 0.5,中间剩余位置的概率非 0 即 1。
80%的数据,?,? ≤ 50。
对于100%的数据,1 ≤ ? ≤ 200,1 ≤ ? ≤ 50。
/* 暴力50分 正解是DP,f[i][j]表示i-j符合要求且是题目中第一种情况的概率,g[i][j]是第二种情况的概率,这么些事为了防止当出现(……)(……)(……)的情况时,枚举断点时会重复数。枚举时只枚举前半段是第一种情况,后半段是第二种情况的。 */ #include<cstdio> #define N 210 #define M 60 using namespace std; double l[N][M],r[N][M],f[N][N],g[N][N]; int n,m; int main(){ freopen("brackets.in","r",stdin); freopen("brackets.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%lf%lf",&l[i][j],&r[i][j]); } } for(int i=0;i<n;i++) f[i+1][i]=1.0; for(int len=2;len<=n;len+=2){ for(int i=1;i<=n-len+1;i++){ for(int j=1;j<=m;j++) f[i][i+len-1]+=(f[i+1][i+len-2]+g[i+1][i+len-2])*l[i][j]*r[i+len-1][j]; for(int j=i+1;j<=i+len-2;j+=2) g[i][i+len-1]+=f[i][j]*(f[j+1][i+len-1]+g[j+1][i+len-1]); } } printf("%.5lf",f[1][n]+g[1][n]); return 0; }