题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4055

题目大意:

给一个只含‘I','D','?'三种字符的字符串,I表示当前数字大于前面的数字,D表示当前的数字小于前面一位的数字,?表示当前位既可以小于又可以大于。

问1~n的排列中有多少个满足该字符串。

解题思路:

计数dp.

dp[i][j]表示长度为i字符串,最后一个数为j时,能达到满足给定字符串的1~i+1的排列个数。

转移方程:

当S[i]='I'时,当前如果为j的话,前面的一位肯定要小于j,dp[i][j]+=Mi[j-1] ; //Mi[i]表示前面一位下标小于等于i dp[][1~i]的和

当S[i]='D'时,dp[i][j]+=(la-Mi[j-1]);  //前一位要大于等于j

当S[i]='?'时,dp[i][j]+=la; //la表示前一位所有的状态总和.

注意递推的时候,前i位只和相对大小有关,与绝对大小无关,所以都用1~i表示,当增加一位时,就变成了1~i+1,如果当前为j,前面的小于j的状态不变,大于等于j的状态k所表示的值 现在表示k+1的值,这样就从1~i等价的转化成了1~i+1,这样考虑就不用考虑1~n的放法了,递推到n位时肯定都是1~n了。

代码:

  1. #include <iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. #include<cstdlib>
  7. #include<cctype>
  8. #include<map>
  9. #include<vector>
  10. #include<set>
  11. #include<queue>
  12. #include<string>
  13. using namespace std;
  14.  
  15. const int INF = 0x3f3f3f3f;
  16. const double eps = 1e-6;
  17. const double PI = acos(-1.0);
  18. typedef __int64 ll;
  19. //#pragma comment(linker, "/STACK:1024000000,1024000000")
  20. /*
  21. freopen("data.in","r",stdin);
  22. freopen("data.out","w",stdout);
  23. */
  24.  
  25. #define M 1000000007
  26. #define Maxn 1100
  27. char sa[Maxn];
  28. int dp[Maxn][Maxn]; //dp[i][j]表示有i个字符,当前数字为j时,所有的总数
  29. //注意有i个字符说明前面一共有1~i+1个不同的数字,dp[i-1]共有1~i个数字,
  30. //建立递推时,如果当前为j,则前面小于j的不变,大于等于j的全部加一,这样就从1~i变成了1~i+1
  31. int la;
  32. int Mi[Maxn][2]; //Mi[i]表示上一个dp[i-1]下标小于等于j的值的总和
  33.  
  34. int main()
  35. {
  36. while(~scanf("%s",sa+1))
  37. {
  38. int len=strlen(sa+1);
  39. for(int i=0;i<=len+10;i++) //初始化
  40. {
  41. Mi[i][0]=Mi[i][1]=0;
  42. for(int j=0;j<=len+10;j++)
  43. dp[i][j]=0;
  44. }
  45. dp[0][1]=1; //没有字符时,有一个数 且这个数为1
  46. la=1;
  47. Mi[1][0]=1; //下标小于等于1的有一个
  48. int pp=0;
  49.  
  50. for(int i=1;i<=len;i++)
  51. {
  52. pp=pp^1; //当前状态
  53. int n=i+1;//当前为可能的取值,注意前面的之和相对大小有关
  54. ll cur=0;
  55. for(int j=1;j<=n;j++) //枚举当前位的数值
  56. {
  57. if(sa[i]=='I') //如果为增的话,前面的肯定是小于j的
  58. dp[i][j]=(dp[i][j]+Mi[j-1][pp^1])%M;
  59. else if(sa[i]=='D') //减的话,前面是大于等于j的,加1后就变成了大于j的了
  60. dp[i][j]=(dp[i][j]+(la-Mi[j-1][pp^1])%M+M)%M;
  61. else //如果无所谓的话,前面所有1-n-1个状态都行
  62. dp[i][j]=(dp[i][j]+la)%M; //用一个la记录
  63. Mi[j][pp]=(Mi[j-1][pp]+dp[i][j])%M;//求出当前的Mi
  64. cur=(cur+dp[i][j])%M; //求出当前的la
  65. }
  66. la=cur; //这题卡常数,多了几个循环都不行
  67. }
  68. ll ans=0;
  69. for(int i=1;i<=len+1;i++) //枚举最后的能够占有的值
  70. ans=(ans+dp[len][i])%M;
  71. printf("%d\n",ans);
  72. }
  73. return 0;
  74. }

计数dp-hdu-4054-Number String的更多相关文章

  1. HDU 4054 Number String

    HDU 4054 Number String 思路: 状态:dp[i][j]表示以j结尾i的排列 状态转移: 如果s[i - 1]是' I ',那么dp[i][j] = dp[i-1][j-1] + ...

  2. HDU 4055 Number String dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4055 Number String Time Limit: 10000/5000 MS (Java/O ...

  3. hdu 4055 Number String(有点思维的DP)

    Number String Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  4. hdu 4055 Number String (基础dp)

    Number String Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  5. hdu 4055 Number String

    Number String http://acm.hdu.edu.cn/showproblem.php?pid=4055 Time Limit: 10000/5000 MS (Java/Others) ...

  6. HDU 4055 Number String(DP计数)

    题意: 给你一个含n个字符的字符串,字符为'D'时表示小于号,字符为“I”时表示大于号,字符为“?”时表示大小于都可以.比如排列 {3, 1, 2, 7, 4, 6, 5} 表示为字符串 DIIDID ...

  7. HDU 4055 Number String (计数DP)

    题意:由数字1到n组成的所有排列中,问满足题目所给的n-1个字符的排列有多少个,如果第i字符是‘I’表示排列中的第i-1个数是小于第i个数的. 如果是‘D’,则反之. 析:dp[i][j] 表示前 i ...

  8. hdu 4055 Number String(dp)

    Problem Description The signature of a permutation is a string that is computed as follows: for each ...

  9. HDU 4055 Number String:前缀和优化dp【增长趋势——处理重复选数】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4055 题意: 给你一个由'I', 'D', '?'组成的字符串,长度为n,代表了一个1~n+1的排列中 ...

  10. hdu 4055 Number String(递推DP)

    给一个只含‘I','D','?'三种字符的字符串,I表示当前数字大于前面的数字,D表示当前的数字小于前面一位的数字,?表示当前位既可以小于又可以大于. 问1~n的排列中有多少个满足该字符串. http ...

随机推荐

  1. 绑定下拉框时避免触发SelectedIndexChanged事件

    在从数据库读取数据集绑定到下拉框时会立即触发其SelectedIndexChanged事件造成异常,可对其SelectedIndexChanged事件采取先解除后附加的方法解决. cmbXl_gt.V ...

  2. [css][移动设备]禁止横竖屏时内容自动调整

    参考:http://www.kankanews.com/ICkengine/archives/106643.shtml iOS下当竖屏转向横屏的时候,发现内容字体会自动变大,通过各种方法设置字体大小都 ...

  3. SQL Server 2008无日志文件附加数据库

    1.新建一个同名数据库. 2.停止数据库服务,覆盖新建的数据库主文件(小技巧:最好放在同一个磁盘里面,把新建的数据库主文件删掉或移开,再把要恢复的数据库主文件剪切过去,这样就可以节省时间.) 3.启动 ...

  4. HDU1106

    为了给学弟学妹讲课,我又水了一题-- 1: import java.util.*; 2: import java.io.*; 3: 4: public class HDU1106 5: { 6: pu ...

  5. 在浏览器控制台调试php程序

    jsp中用system.out.print如果是在eclipse中调试的话,eclipse会自动拦截系统输出流, 然后输出在控制台中,而http输出流则不受影响,php好像无此功能, PHP是一种服务 ...

  6. C++ Primer 随笔 Chapter 2 变量和基本类型

    2.1C++内置类型 C++ 算术类型 类型 含义 最小存储空间(随机器不同而不同) bool 布尔型 --- char 字符型 8位 wchar_t 宽字符型 16位 short 短整型 16位 i ...

  7. hdu-1890-Robotic Sort splay区间翻转

    题意: 依次找第i大的数下标pos[i],然后将区间[i,pos[i]]翻转 分析: splay树区间翻转 // File Name: ACM/HDU/1890.cpp // Author: Zlbi ...

  8. Linux下的定时器:alarm()与setitimer()

    Linux下的定时器有两种,以下分别介绍: 1.alarm 如果不要求很精确的话,用alarm()和signal()就够了 unsigned int alarm(unsigned int second ...

  9. (转载)eclipse 快捷键大全,eclipse查找类,文件,添加注释

    (转载)http://hi.baidu.com/fegro/item/8224c8c28b174627ee466598   /* ----------------------------------- ...

  10. 网络流(最大流) CQOI 2015 BZOJ 3931 网络吞吐量

    3931: [CQOI2015]网络吞吐量 Description 路由是指通过计算机网络把信息从源地址传输到目的地址的活 动,也是计算机网络设计中的重点和难点.网络中实现路由转发的硬件设备称为路由器 ...