hdu 5396 Expression(区间dp+组合数)
2015-08-26 18:43
162 查看
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5396
解题思路:
题目大意:
题目大意:有n个数,和n-1个符号('+','-','*')形成一个表达式,现在问对于不同的运算序列,得到的结果的总和是多少(结果为非负整数,对1e9+7取余)
dp[i][j]记录在区间l到r内的各种不同的运算序列的结果的和。
官方题解:
记dp_{l,r}dpl,r表示l,rl,r这段数能形成的答案总和。
枚举最后一步操作kk,如果是乘法,答案为dp_{l,k}*dp_{k+1,r}dpl,k∗dpk+1,r,由于分配率这个会乘开来。如果是加法那么是dp_{l,r}*(r-k-1)!+dp_{k+1,r}*(k-l)!dpl,r∗(r−k−1)!+dpk+1,r∗(k−l)!,即要乘上右边k+1,rk+1,r这些数所有可行的方案数,减法同理。最后乘上{r-l-2
\choose k-l}(k−lr−l−2),即把两边操作合起来的方案数。
答案为dp_{1,n}dp1,n。
算法思想:
首先长度len是1的时候,dp[i][i] = a[i]
之后dp[i][j] = ∑ (dp[i][k] 和 dp[k+1][j] 合并而成),k为[i,j]范围内的运算符号,那么分三种情况:
1、'+'
对于dp[i][k]共有k-l个符号,也就是有(k-i)!种不同的运算序列,dp[k+1][j]有(j-k-1)!种运算序列,那么对于不同的运算序列得到的值应该累加,所以累加的和为dp[i][k]*(j-k-1)! + dp[k+1][j]*(k-i),同时还要注意,这种运算序列是符号j的左右两侧分开考虑的,如果交叉考虑,只要各自相对的运算顺序没变,那么值就不会变,但会形成新的一种运算方法,所以最终的值还要再乘以C(j-i-1 , k-i)。
2、'-'
和加法基本相同,只需要把加换成减。
3、'*'
对于乘法,我们需要的结果是左右表达式中的各种运算方式得到的值分别相乘然后累加和,这个结果就可以直接转化为dp[i][k]*dp[k+1][j],同样我们还需要对最终的结果乘以C(j-i-1 , k-i)
注意取余,最终的dp[0][n-1]就是结果
AC代码:
http://acm.hdu.edu.cn/showproblem.php?pid=5396
解题思路:
题目大意:
题目大意:有n个数,和n-1个符号('+','-','*')形成一个表达式,现在问对于不同的运算序列,得到的结果的总和是多少(结果为非负整数,对1e9+7取余)
dp[i][j]记录在区间l到r内的各种不同的运算序列的结果的和。
官方题解:
记dp_{l,r}dpl,r表示l,rl,r这段数能形成的答案总和。
枚举最后一步操作kk,如果是乘法,答案为dp_{l,k}*dp_{k+1,r}dpl,k∗dpk+1,r,由于分配率这个会乘开来。如果是加法那么是dp_{l,r}*(r-k-1)!+dp_{k+1,r}*(k-l)!dpl,r∗(r−k−1)!+dpk+1,r∗(k−l)!,即要乘上右边k+1,rk+1,r这些数所有可行的方案数,减法同理。最后乘上{r-l-2
\choose k-l}(k−lr−l−2),即把两边操作合起来的方案数。
答案为dp_{1,n}dp1,n。
算法思想:
首先长度len是1的时候,dp[i][i] = a[i]
之后dp[i][j] = ∑ (dp[i][k] 和 dp[k+1][j] 合并而成),k为[i,j]范围内的运算符号,那么分三种情况:
1、'+'
对于dp[i][k]共有k-l个符号,也就是有(k-i)!种不同的运算序列,dp[k+1][j]有(j-k-1)!种运算序列,那么对于不同的运算序列得到的值应该累加,所以累加的和为dp[i][k]*(j-k-1)! + dp[k+1][j]*(k-i),同时还要注意,这种运算序列是符号j的左右两侧分开考虑的,如果交叉考虑,只要各自相对的运算顺序没变,那么值就不会变,但会形成新的一种运算方法,所以最终的值还要再乘以C(j-i-1 , k-i)。
2、'-'
和加法基本相同,只需要把加换成减。
3、'*'
对于乘法,我们需要的结果是左右表达式中的各种运算方式得到的值分别相乘然后累加和,这个结果就可以直接转化为dp[i][k]*dp[k+1][j],同样我们还需要对最终的结果乘以C(j-i-1 , k-i)
注意取余,最终的dp[0][n-1]就是结果
AC代码:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; const int MOD = 1e9+7; const int maxn = 100; ll c[maxn+5][maxn+5],f[maxn+5]; ll dp[maxn+5][maxn+5]; char op[maxn+5]; void init(){ for(int i = 0; i <= maxn; i++){ c[i][0] = c[i][i] = 1; for(int j = 1; j <= i; j++) c[i][j] = (c[i-1][j]+c[i-1][j-1])%MOD; } f[0] = 1; for(int i = 1; i <= maxn; i++) f[i] = f[i-1]*i%MOD; } int main () { init (); int n; while (~scanf("%d",&n)) { memset(dp, 0, sizeof(dp)); for (int i = 0; i < n; i++) scanf("%d", &dp[i][i]); getchar(); gets(op); for (int i = n-1; i >= 0; i--) { for (int j = i + 1; j < n; j++) { int len = j - i - 1; for (int k = i; k < j; k++) { int l = k - i, r = j - k - 1; ll ret = 0; if (op[k] == '+') { ret = (ret + dp[i][k] * f[r]) % MOD; ret = (ret + dp[k+1][j] * f[l]) % MOD; } else if (op[k] == '-') { ret = (ret + dp[i][k] * f[r]) % MOD; ret = ((ret - dp[k+1][j] * f[l]) % MOD + MOD) % MOD; } else if (op[k] == '*') ret = dp[i][k] * dp[k+1][j] % MOD; dp[i][j] = (dp[i][j] + ret * c[len][l]) % MOD; } //printf("%d %d: %d\n", i, j, dp[i][j]); } } printf("%lld\n", dp[0][n-1]); } return 0; }
相关文章推荐
- Kafka简介及集群搭建详细流程
- Provisioning Services 7.6 入门到精通系列之六:目标设备安装
- Linux之文件访问权限管理
- MySQL数据库自动生成并修改随机root密码的脚本
- 事务的ACID
- yii2 访问控制
- ObjectiveC开发教程--如何去除字符串中的空格和回车
- AutocompleteTextView
- 51nod 1391 01串(锻炼思维的好题)
- MUI - 封装localStorage与plus.storage
- 欢迎使用CSDN-markdown编辑器
- POJ 2528 Mayor's posters
- istringstream的用法
- ZOJ 3810 A Volcanic Island
- lua中os.clock()为何会返回负值
- Spring 事务源码分析——Hibernate篇
- php的表单安全处理
- php+mysqli实现批量执行插入、更新及删除数据的方法
- 关于烂代码的那些事(上)
- 黑马程序员-Java基础学习第一天总结