Hdu 5396 Expression (区间Dp)
2015-08-19 13:17
405 查看
题目链接:
Hdu 5396 Expression
题目描述:
给出n个数字,n-1个符号。问不同的操作顺序得到的所有结果相加是多少?
解题思路:
n取值范围[1,100],肯定不能强行搜索。比赛的时候队友在这个题目上卡了好久,扎扎赛后决定把这个补了来拯救我快要卡哭了的队友。可以看出这个是明显的区间dp题目,dp[l][i]代表[l,r]这个区间内不同组合结果的总和。然后我们就要讨论怎么进行状态转移咯。由于'*', '-', '+'运算的性质,我们要分别对他们进行讨论。
'*':有乘法的分配律可知,dp[l][r] = dp[l][k]*dp[k+1][r];
'-'/'+':加减法就没有分配律咯,所以要分别在两边乘上一个阶乘,让两边的不同结果一一对应匹配。
最后还要再乘上一个组合数,因为左右两边操作符在之前是有顺序的,但是两边合并以后两边的操作符在保证了自己的顺序后是可以混合的,也就是要在r - l + 1个位置里挑出k-l个位置。
Hdu 5396 Expression
题目描述:
给出n个数字,n-1个符号。问不同的操作顺序得到的所有结果相加是多少?
解题思路:
n取值范围[1,100],肯定不能强行搜索。比赛的时候队友在这个题目上卡了好久,扎扎赛后决定把这个补了来拯救我快要卡哭了的队友。可以看出这个是明显的区间dp题目,dp[l][i]代表[l,r]这个区间内不同组合结果的总和。然后我们就要讨论怎么进行状态转移咯。由于'*', '-', '+'运算的性质,我们要分别对他们进行讨论。
'*':有乘法的分配律可知,dp[l][r] = dp[l][k]*dp[k+1][r];
'-'/'+':加减法就没有分配律咯,所以要分别在两边乘上一个阶乘,让两边的不同结果一一对应匹配。
最后还要再乘上一个组合数,因为左右两边操作符在之前是有顺序的,但是两边合并以后两边的操作符在保证了自己的顺序后是可以混合的,也就是要在r - l + 1个位置里挑出k-l个位置。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 110; const int mod = 1000000007; typedef long long LL; LL dp[maxn][maxn], C[maxn], b[maxn]; char op[maxn]; //组合数用费马小定理取余 LL Pow (LL x) { LL res = 1; LL n = mod - 2; while (n) { if (n % 2) res = (res * x) % mod; x = (x * x) % mod; n /= 2; } return res; } void init () {//阶乘表 C[0] = b[0] = 1; for (int i=1; i<maxn; i++) { C[i] = (C[i-1] * i) % mod; b[i] = Pow (C[i]); } } LL Sum (LL x, LL y, char p) { if (p == '+') return (x + y + mod) % mod; if (p == '-') return (x - y + mod) % mod; if (p == '*') return (x * y + mod) % mod; } int main () { int n; init (); while (scanf ("%d", &n) != EOF) { memset (dp, 0, sizeof(dp)); for (int i=0; i<n; i++) { scanf ("%lld", &dp[i][i]); dp[i][i] = (dp[i][i] + mod) % mod; } scanf ("%s", op+1); for (int j=0; j<n; j++) {//区间终点 for (int i=j-1; i>=0; i--)//区间起点 for (int k=j; k>i; k--) {//枚举区间内最后一个运算的符号 LL s1, s2; if (op[k] == '*') { s1 = dp[i][k-1]; s2 = dp[k][j]; } else {//加减法要乘两边符号的贡献 s1 = (dp[i][k-1] * C[j-k] + mod) % mod; s2 = (dp[k][j] * C[k-i-1] + mod) % mod; } s1 = (Sum(s1, s2, op[k]) * (C[j-i-1] * b[j-k] % mod * b[k-i-1] % mod) + mod) % mod; //取余的时候一定要把组合数括起来,要不会死的很惨的, dp[i][j] = (dp[i][j] + s1 + mod) % mod; } } printf ("%lld\n", dp[0][n-1]); } return 0; }
相关文章推荐
- 6.7Pointers to Functions
- 使用JPA来执行本地SQL语句查询
- 2015上半年手机GPU排行榜
- WIN版的Jenkins Master加入LINUX的SLAVE节点,并作C++程序的集成交付
- HTTP 错误 404.17 - Not Found
- HDU 1312 Red and Black 【DPS】
- 一个初学者对于MVC架构的理解
- Android三种播放视频的方式
- [LeetCode] Ugly Number 丑陋数
- 远程读取XML根级别上的数据无效。 行 1,位置 1
- android 自定义字体
- Android中访问资源的几种方式总结
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- 时间转换<将秒转换为天、小时、分钟>
- 模拟发送鼠标消息示例代码
- leveldb和rocksdb在大value场景下的一些问题
- aauto学习系列之<8>函数1
- mysql除法精度
- 数独游戏java版(二)--界面实现
- linux 使用 lockf命令防止脚本重复运行