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

  

posted @ 2015-08-19 13:39  Painting、时光  阅读(116)  评论(0编辑  收藏  举报