数位dp浅谈(hdu3555)

数位dp简介:

数位dp常用于求区间内某些特殊(常关于数字各个数位上的值)数字(比如要求数字含62,49);

常用解法:

数位dp常用记忆化搜索或递推来实现;

由于记忆化搜索比较好写再加上博主比较蒟,所以本文基本只介绍用记忆化搜索实现的数位dp;

记搜写法:

一般记搜写法会暴力搜索每个数的每一位,如果满足特征就加入答案;

而搜索中或搜完后用一个dp数组来存某一区间的特殊数的数量,防止多次重复搜索TLE;

空口说比较苍白无力,举个例子:比如要在1到r中找含49(4和9要连在一起)的特殊数的数量;

搜索时,传递当前要填的数字在数中的位置(pos),上一个填的数值(pre),之前有没有出现49(have),以及填的数有没有限制(limit);

pos用来观察这个数有几位,有没有达到范围;

pre用来判断之前的数是不是4,从而来判断如果当前位填9,是否能出现49

have用记录是否出现 49,在搜的过程中就可以记录特殊数的数量;

limit的作用是防止数过大超过范围(具体操作见下文例题);

dp[pos][pre]存当当前要填的数的位置为pos,上一个数为pre时特殊值的数量;

例题(hdu3555):

题目大意是给出n,给出n个范围1—r,输出每个范围中含49的数的数量

思路就是上面的例子,这里仔细介绍一下limit的用法;

比如r=1234,当pos=3(pos=1时是个位,从第一位开始搜),如果pre=1,那么这一位就只能填0—2了,limit就是记录之前填的数和上界是否相同,而传递也很简单,如果limit=true而且当前要填的数等于给定范围的pos位上的数时,limit仍然是true,否则就是false;

注意!

1、数位dp基本上的题都要开long long,不然暴力就能过了;

2、具体题目时要注意dp的含义防止重复加;

下面附上丑陋的代码:

 1 #include<cstdio>
 2 using namespace std;
 3 #define int long long 
 4 const int MAXN=20;
 5 int n,r,t,digit[MAXN],dp[MAXN][MAXN];
 6 //digit是上界各个位置的数
 7 //dp记录搜过的值 
 8 int dfs(int pos,int pre,bool limit)
 9 //我这里的记搜和上面讲的略有不同,求的是不满足条件的数,如果出现49了就不继续做 
10 //最后答案就是上界减去搜出来的数值 
11 //这样可以在记搜时去除一维,加快一点速度 
12 {
13     if(pos==0) return 1; 
14     if(!limit&&dp[pos][pre]!=0)
15     //这里的!limit是因为如果当前填的数是有范围的(不能大于上界),就不满足一般的规律 
16     {
17         return dp[pos][pre];
18     }
19     int up=9;
20     if(limit) up=degit[pos];
21     //如果有限制就把上界设为范围的值 
22     int ans=0;
23     for(int i=0;i<=up;++i)
24     if(pre==4&&i==9)
25         continue;
26     //满足条件就跳出 
27     else
28     {
29         ans+=dfs(pos-1,i,limit&&(i==digit[pos]));
30     }
31     if(!limit)
32     //和上面的!limit同一个道理 
33     {
34         dp[pos][pre]=ans;
35     }
36     return ans;
37 }
38 void solve(int x)
39 {
40     t=0;
41     int xx=x;
42     while(x>0)
43     {
44         ++t;
45         digit[t]=x%10;
46         x=x/10;
47     }
48     printf("%lld\n",xx-dfs(t,0,1)+1);
49 }
50 main()
51 {
52     scanf("%lld",&n);
53     for(int i=1;i<=n;++i)
54     {
55         scanf("%lld",&r);
56         solve(r);
57     }
58 }
posted @ 2018-09-29 21:21  DFSlover  阅读(503)  评论(5编辑  收藏  举报

Contact with me