计数dp hdu 4055 Number String
2016-01-03 20:20
267 查看
嗯,什么是计数dp我也不知道,这是第一次遇见类似的题目。
题意:给一个只含‘I','D','?'三种字符的字符串,I表示当前数字大于前面的数字,D表示当前的数字小于前面一位的数字,?表示当前位既可以小于又可以大于。问1~n的排列中有多少个满足该字符串。
分析:看题意就觉得像是dp,果然是的。dp[i][j]表示的是前i个数字的排列中以数字j结尾的排列个数。
那么递推关系是什么呢。
当str[i-1] == 'I' 时表示第i为的数字大于i-1位的数字,我们可以看到,dp[i][j] = dp[i-1][1]+dp[i-1][2]+......+dp[i-1][j-1];
当str[i-1] == 'D' 时表示第i为的数字小于i-1位的数字,我们可以看到,dp[i][j]
= dp[i-1][j+1]+dp[i-1][j+2]+......+dp[i-1][i]; 但是我们可以注意到,
dp[i-1][i]是不存在的,前i-1个数字中是不会有i数字出现的。我们考虑到,将前i-1个数字的所有排列中,大于等于j的数字都加1的话,是不会改变排列方案数的,所以这时候dp[i][j]
= dp[i-1][j]+dp[i-1][j+1]+......+dp[i-1][i-1];
但是这样的话复杂度是O(n^3),会超时,所以我们增加一个数组sum[i][j]来记录前缀和就可以了。sum[i][j]
表示的是dp[i][1]+dp[i][2]+......+dp[i][j]
题意:给一个只含‘I','D','?'三种字符的字符串,I表示当前数字大于前面的数字,D表示当前的数字小于前面一位的数字,?表示当前位既可以小于又可以大于。问1~n的排列中有多少个满足该字符串。
分析:看题意就觉得像是dp,果然是的。dp[i][j]表示的是前i个数字的排列中以数字j结尾的排列个数。
那么递推关系是什么呢。
当str[i-1] == 'I' 时表示第i为的数字大于i-1位的数字,我们可以看到,dp[i][j] = dp[i-1][1]+dp[i-1][2]+......+dp[i-1][j-1];
当str[i-1] == 'D' 时表示第i为的数字小于i-1位的数字,我们可以看到,dp[i][j]
= dp[i-1][j+1]+dp[i-1][j+2]+......+dp[i-1][i]; 但是我们可以注意到,
dp[i-1][i]是不存在的,前i-1个数字中是不会有i数字出现的。我们考虑到,将前i-1个数字的所有排列中,大于等于j的数字都加1的话,是不会改变排列方案数的,所以这时候dp[i][j]
= dp[i-1][j]+dp[i-1][j+1]+......+dp[i-1][i-1];
但是这样的话复杂度是O(n^3),会超时,所以我们增加一个数组sum[i][j]来记录前缀和就可以了。sum[i][j]
表示的是dp[i][1]+dp[i][2]+......+dp[i][j]
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <queue> #include <algorithm> using namespace std; #define mod 1000000007 int const maxn = 1005; char str[maxn]; long long dp[maxn][maxn]; long long sum[maxn][maxn]; //dp[i][j] 表示的是前i个数字的排列中以数字j结尾的排列个数 //sum[i][j] 表示的是dp[i][1]+dp[i][2]+......+dp[i][j] int main() { while(scanf("%s",str+1)!=EOF) { int n = strlen(str+1)+1; //要计算的长度比字符串的长度大1 dp[1][1] = 1 ; //一个数字以1结尾有一种情况 sum[1][1] = 1 ; for(int i = 2 ; i <= n ; i++) { for(int j = 1 ; j <= i ; j++) { if(str[i-1]=='I') { dp[i][j] = sum[i-1][j-1]; } else if(str[i-1]=='D') { dp[i][j] = ( sum[i-1][i-1] - sum[i-1][j-1] + mod ) % mod ; } else dp[i][j] = sum[i-1][i-1] ; sum[i][j] = (dp[i][j] + sum[i][j-1] + mod ) % mod ; } } printf("%I64d\n",sum ); } return 0; }
相关文章推荐
- Virtual Box 增加虚拟硬盘容量
- android编程中怎么将一个按钮置于最上层
- 请求发送者与接收者解耦——命令模式
- vs2015
- Hadoop集群安装(六)--------CentOS配置SSH无密码登录
- 第六届河南省赛 zzulioj 1488: River Crossing (一维DP)nyoj 716
- Ubuntu 14.04 14.10 samba配置
- IDEA的安装
- 20.2 Windos 中的多线程
- 每日一vim(16-17)Visual模式
- 字符串匹配那些事(一)http://kb.cnblogs.com/page/107856/
- 高手遇事的处理方法
- 树莓派2交叉编译环境
- 应用层协议实现系列(三)——FTPserver之设计与实现
- 理论: 图论(9): 二分图匹配解释
- 解决 appt getting 'android:icon' attribute: attribu
- 8、鼠标控制与32位模式切换
- Ubuntu中使用GitLab Installers一键傻瓜式安装gitlab
- 装饰者模式
- POJ 2135 Farm Tour && HDU 2686 Matrix && HDU 3376 Matrix Again 费用流求来回最短路