数位dp

问题:在一个给定的区间[a,b]内,找满足要求的数。

如果我们用暴力的话一般要考虑数的大小,而数位dp要考虑的确实数的组成。

例如:  递增的  1234  1357  2468

          整除13的  13 26 39

          包含13的  132 2134

          双峰的   152630  243052

 

如果数的位数大于100,暴力肯定Over。

数位dp要注意的就是数的组成处理以及数的边界处理。

 

核心思路:记忆化搜索+记录合适状态。数位dp顾名思义就是逐位dp逐位考虑。

举例: [0,8457]内逐位递增的数有多少个。那么我们先对第一位进行处理,即枚举0XXX,1XXX,...8XXX。当我们枚举到第二位的时候。05XX,15XX,25XX...75XX,后面两位XX前的状态量都是5,如果我们已经处理了05XX后面满足要求的数的个数,那么我们15XX,25XX...是不是也可以利用那个已经求得的结果呢,利用深搜的那个结果可以用记忆化搜索预先求得。

开辟空间dp[len][state],表示最后len位前面状态为state时满足要求的数的个数。

 

hdu2089 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089

题目大意:求区间[a,b]内不含4和62的数有多少个。

思路: dp[len][state],state表示后面len位数之前一位那个数是否为6,是则为1不是则为0

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 
 7 int dp[8][2];
 8 int digit[10];
 9 
10 int dfs(int len, int state, int fp)
11 {
12       if(!len) return 1;
13       if(!fp&&dp[len][state]!=-1) return dp[len][state];
14       int ret=0, fpmax=fp?digit[len]:9;
15       for(int i=0; i<=fpmax; i++)
16       {
17           if(i==4||(state&&i==2)) continue;
18           ret+=dfs(len-1,i==6,fp&&i==fpmax);
19       }
20       if(!fp) dp[len][state]=ret;
21       return ret;
22 }
23 
24 int cal(int n)
25 {
26     int len=0;
27     memset(dp,-1,sizeof(dp));
28     while(n)
29     {
30         digit[++len]=n%10;
31         n/=10;
32     }
33     return dfs(len,false,true);
34 }
35 
36 int main()
37 {
38     int a, b;
39     while(scanf("%d%d",&a,&b),a+b)
40     {
41         printf("%d\n",cal(b)-cal(a-1));
42     }
43     return 0;
44 }
View Code

 

hdu3652 

题目大意:求区间[a,b]内包含子串13以及是13的倍数的数有多少个。

思路:dp[len][pre][state],state表示后面len位数之前一位那个数是否为1,是则为1不是则为0,如果已经出现13则为2,pre记录前面各位数的余数。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3652

 

 

转载于:https://www.cnblogs.com/kane0526/p/3546513.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值