【题意】: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