HDU5396——区间DP+排列组合——Expression
http://acm.hdu.edu.cn/showproblem.php?pid=5396
/* 题目大意:给你一些表达式,问你不考虑乘除优先级,问所有可能性之和为多少 比方说 (1+2)+3 1+(2+3) 算不同 定义dp[i][j] 表示从i到j之和 令k为两个表达式之间的符号 如果k为* 状态转移方程 dp[i][j] = (dp[i][j] + dp[i][k]*dp[k+1][j]) 两者情况之积 (1+2*3)*(2+3+4) 左边有两种,右边有两种,那么就是四,因为×肯定是最后一步做的 如果k为+/- 状态转移方程 dp[i][j] = (dp[i][j] + dp[i][k]*(j-k-1) + dp[k+1][j]*(k-i)) 和的话 (1+2*3) + (2+3+4) 加是最后一步做的,左边的数会加(j-k-1)!次,即右边的全排列的随时可以加,后面同理 最后都要乘以一个组合数comb[j-i-1][k-i]的原因: 假设我左边两个符号是 + * 右边是 + + 在已经确定了什么必须与什么相乘情况下,只能是选左或者选右 就是 (1+2*3)*(2+3+4) 我们假设顺序必须是2*3 然后 1+(2*3) 右边是(2+3)然后(2+3)+4,但是我们2*3之后可以选择右边(2+3)而不选择1+(2*3)那么这些排列情况需要考虑 我们已经知道了左边的乘法必须先于+法,右边的第一个加法先于第二个加法 那么可以看成一共有4个位置我要选择两个位置把第一个放进去并且满足,那第二个是不是已经确定了 ---- *+-- *-+- *--+ -*+- -*-+ --*+ 6种 */ /************************************************ * Author :Powatr * Created Time :2015-8-19 12:27:50 * File Name :HDU5396.cpp ************************************************/ #include <cstdio> #include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue> #include <deque> #include <stack> #include <list> #include <map> #include <set> #include <bitset> #include <cstdlib> #include <ctime> using namespace std; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 typedef long long ll; const int MAXN = 1e2 + 10; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; ll comb[MAXN][MAXN]; ll fac[MAXN]; void inti() { for(int i = 0 ; i <= 100; i++){ comb[i][0] = comb[i][i] = 1; for(int j = 1; j <= i; j++){ comb[i][j] = (comb[i-1][j-1] + comb[i-1][j])%MOD; } } fac[0] = 1; for(int i = 1; i <= 100; i++){ fac[i] = fac[i-1] * i % MOD; } } int main(){ int n; char s[MAXN]; int a[MAXN]; ll dp[MAXN][MAXN]; inti(); while(~scanf("%d", &n)){ for(int i = 1; i <= n; i++) scanf("%d", &a[i]); scanf("%s", s+1); for(int i = n ; i >= 1; i--){ dp[i][i] = a[i]; for(int j = i + 1; j <= n; j++){ dp[i][j] = 0; for(int k = i; k <= j; k++){ if(s[k] == '*'){ dp[i][j] = (dp[i][j] + dp[i][k]*dp[k+1][j]%MOD*comb[j-i-1][k-i])%MOD; } else if(s[k] == '+'){ dp[i][j] = (dp[i][j] + (dp[i][k]*fac[j-k-1] + dp[k+1][j]*fac[k-i])%MOD*comb[j-i-1][k-i])%MOD; } else if(s[k] == '-'){ dp[i][j] = (dp[i][j] + (dp[i][k]*fac[j-k-1] - dp[k+1][j]*fac[k-i])%MOD*comb[j-i-1][k-i])%MOD; } } } } printf("%I64d\n", (dp[1][n]+MOD)%MOD); } return 0; }