【题意】:click here~~
【题目大意】:
给你一个一行包含n(2=<n<=100)个数字的式子,和一个字符串(2=<s<=100),字符串里包含三种运算符号:+,-,*,且s=n-1,也就是说在每两个数字之间,插入n-1个符号,位置已经在输入的时候固定了,现在你要做的就是可以自由安排符号的运算顺序,每轮选择之后,将会得到一个结果,求所有的结果的和
【思路】:区间DP:
先贴一下题解(感觉题解有个地方写错了):
设DP[l][r]:表示区间【l,r】这段里面能形成的答案的总数。
枚举最后一步的操作k,那么对乘法:答案为DP[i,k]*DP[k+1,r],由于分配律这个会乘开来,如果是加法,那么答案就是DP[i][k]*(j-k-1)!+DP[k+1][j]*(k-i)!。减法同理
最后乘上C(j-i-1,k-i)。最后答案就是DP[1][n]。
代码:
/**********************
*hdu 5396
*区间DP
*注意:加号和减号,符号不同,debug半天!
*
*********************/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MOD = 1e9 + 7;
const int N = 233;
char op[N];
LL dp[N][N];
int n;
LL pai[N];
LL zuhe[N][N];
void init() ///预处理 排列 和组合
{
for(int i=0; i<N; i++)for(int j=0; j<=i; j++){
if(i==j ||j==0) zuhe[i][j] = 1;
else zuhe[i][j] = (zuhe[i-1][j-1] + zuhe[i-1][j]) % MOD;
}
pai[0] = 1;
for (int i=1; i<N; i++) pai[i] = pai[i-1] * i % MOD;
}
int main()
{
init();
while (scanf("%d", &n)==1) {
memset(dp, 0, sizeof dp);
for (int i=1; i<=n; i++) scanf("%I64d", &dp[i][i]);
scanf("%s", op+1);
for (int L = 2; L <= n; L ++)
for (int i=1;i+L-1<=n;i++) {
int j = i + L - 1;
dp[i][j] = 0;
for (int k=i;k<j;k++) {
LL ans;
if (op[k]=='*'){
ans = (dp[i][k] * dp[k+1][j]) % MOD;
}
if (op[k]=='+'){
ans= (dp[i][k]*pai[j-k-1] + dp[k+1][j] * pai[k-i])%MOD;
}
if (op[k]=='-'){///注意这里是减号!!!
ans= (dp[i][k]*pai[j-k-1] - dp[k+1][j] * pai[k-i] )%MOD;
}
dp[i][j] = (dp[i][j] + ans* zuhe[j-i-1][k-i]) % MOD;
}
}
printf("%I64d\n", (dp[1][n] + MOD) %MOD );
}
return 0;
}
/*
3
3 2 1
-+
5
1 4 6 8 3
+*-*
*/版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 5396 Expression (MUT#9 区间DP)
原文:http://blog.csdn.net/u013050857/article/details/47780023