hdu 2089(数位dp)

这道题应该是最简单的数位dp了,看了09年的刘聪的国家集训队论文,入门了一下数位dp。解决这道题还是花了我好长的一段时间。

这里就先讲一下我是如何用数位dp解这道题的,感觉后面还是要写一篇数位dp的总结。首先是状态的确定,数位dp的基本状态往往是dp[i, ...]i表示枚举到的位数,后面是需要的状态。对于这道题,我列举了一个状态就是dp[i][j]表示枚举到第i位第一个数字是j所包含的合法数字数。

程序结构:

初始化的时候把dp数组先预处理出来,后面写个solve(x)表示当前数前面的合法数个数。那ans = solve(b+1)-solve(a)。

关键在于处理solve(x)的计算。首先是枚举每一位,然后是枚举每一位可能出现的值,注意在枚举值得时候一旦前面已经枚举的数中已经出现4或者是62直接break。

若是前一位确定为6这一位枚举到2 或者 这一位为4 continue,这应该都比较好理解。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <algorithm>
 7 #define LEN 30
 8 using namespace std;
 9 
10 int a, b, dp[LEN][LEN];
11 
12 void init()
13 {
14     memset(dp, 0, sizeof dp);
15     for(int i=0; i<LEN; i++){
16         if(i!=4) dp[1][i] = 1;
17     }
18     for(int i=2; i<LEN; i++){
19         for(int j=0; j<10; j++){
20             if(j==4) continue;
21             for(int k=0; k<10; k++){
22                 if((j==6 && k==2) || k==4)continue;
23                 dp[i][j] += dp[i-1][k];
24             }
25         }
26     }
27 }
28 
29 
30 int solve(int x)
31 {
32     char str[100] = {0};
33     sprintf(str+1, "%d", x);
34     int len = strlen(str+1), ret = 0;
35     for(int i=len; i>=1; i--){
36         int pos = len-i+1, num = str[pos]-'0';
37         for(int j=0; j<num; j++){
38             if(j==4 || (j==2 && str[pos-1]=='6'))continue;
39             ret += dp[i][j];
40         }
41         if(num==4 || (num==2 && str[pos-1]=='6')) break;
42     }
43     return ret;
44 }
45 
46 int main()
47 {
48 //    freopen("in.txt", "r", stdin);
49 
50     while(scanf("%d%d", &a, &b)!=EOF)
51     {
52         if(a==0 && b==0)break;
53         init();
54         int ans = solve(b+1) - solve(a);
55         printf("%d
", ans);
56     }
57     return 0;
58 }
View Code
奔跑吧!少年!趁着你还年轻
原文地址:https://www.cnblogs.com/shu-xiaohao/p/3438470.html