HDU 5396 Expression (MUT#9 区间DP)

来源:互联网 发布:js实现pdf在线阅读 编辑:程序博客网 时间:2024/05/18 18:55

【题意】: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;}/*33 2 1-+51 4 6 8 3+*-**/


0 0