数位DP

Posted chaoswr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数位DP相关的知识,希望对你有一定的参考价值。

  萌新第一题:HDU2089 不要62 

技术分享图片
 1 #include <iostream>
 2 #include <string.h>
 3 #include <cstdio>
 4 #include <queue>
 5 #include <math.h>
 6 #include <string>
 7 #include <map>
 8 #include <algorithm>
 9 
10 #define SIGMA_SIZE 26
11 #pragma warning ( disable : 4996 )
12 
13 using namespace std;
14 typedef long long LL;
15 
16 inline LL LMax(LL a,LL b)    { return a>b?a:b; }
17 inline LL LMin(LL a,LL b)    { return a>b?b:a; }
18 inline int Max(int a,int b) { return a>b?a:b; }
19 inline int Min(int a,int b) { return a>b?b:a; }
20 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
21 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
22 const int inf  = 0x3f3f3f3f;
23 const int mod  = 100000000;
24 const int maxn = 1e6+5;
25 const int maxk = 200;
26 
27 int dp[20][2];
28 int num[20];
29 
30 int find( int pos, int pre, int sta, bool limit )
31 {
32     if ( pos == -1 ) return 1;
33     if ( !limit && dp[pos][sta] != -1 ) return dp[pos][sta];
34     int up = limit?num[pos]:9;
35     int tmp = 0; 
36     for ( int i = 0; i <= up; i++ )
37     {
38         if ( pre == 6 && i == 2 ) continue;
39         if ( i == 4 ) continue;
40         tmp += find(pos-1, i, i==6, limit&&i==num[pos]);
41     }
42 
43     if (!limit) dp[pos][sta] = tmp;
44     return tmp;
45 }
46 
47 int solve( int x )
48 {
49     int pos = 0;
50     while(x)
51         { num[pos++] = x % 10; x /= 10; }
52 
53     return find( pos-1, -1, 0, true );
54 }
55 
56 int main()
57 {
58     int lhs, rhs;
59     while ( ~scanf("%d %d", &lhs, &rhs) && lhs && rhs )
60     {
61         memset( dp, -1, sizeof(dp) );
62         printf( "%d\n", solve(rhs)-solve(lhs-1) );
63     }
64     return 0;
65 }
View Code

  萌新第二题:HDU3652 B数...

 有点巧妙啊,第一题只是相当于把题解抄下来了,再做这道题稍微有点感觉了,详细见注释 

技术分享图片
 1 #include <iostream>
 2 #include <string.h>
 3 #include <cstdio>
 4 #include <queue>
 5 #include <math.h>
 6 #include <string>
 7 #include <map>
 8 #include <algorithm>
 9 
10 #define SIGMA_SIZE 26
11 #pragma warning ( disable : 4996 )
12 
13 using namespace std;
14 typedef long long LL;
15 
16 inline LL LMax(LL a,LL b)    { return a>b?a:b; }
17 inline LL LMin(LL a,LL b)    { return a>b?b:a; }
18 inline int Max(int a,int b) { return a>b?a:b; }
19 inline int Min(int a,int b) { return a>b?b:a; }
20 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
21 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
22 const int inf  = 0x3f3f3f3f;
23 const int mod  = 100000000;
24 const int maxn = 1e6+5;
25 const int maxk = 200;
26 
27 //dp[i][j][k] i:位数 j:余数 k:0表示前面不是1,1表示前面是1,2表示前面已经有13了
28 int dp[15][15][3];
29 int bit[15];
30 
31 int find(int pos, int mod, int pre, bool lim )
32 {
33     if ( pos == -1 ) return ( mod == 0 && pre == 2 );
34 
35     // 务必理解什么是记忆化
36     if ( !lim && dp[pos][mod][pre] != -1 ) return dp[pos][mod][pre];
37     
38     int num = lim?bit[pos]:9;
39 
40     int tmp = 0;
41     for ( int i = 0; i <= num; i++ )
42     {
43         int mmod = (mod*10 + i) % 13;    //其实就是做了一个除法,拿笔做演算下,比如计算2333除以13,
44                                         //就知道这一步是什么意思了
45         
46         int ppre = 0;                //初始设为0
47         if ( pre == 0 && i == 1 )    //如果前面不是1,现在是1
48             ppre = 1;
49         if ( pre == 1 && i == 1 )    //如果前面是1,现在还是1
50             ppre = 1;
51         if ( pre == 1 && i == 3 )    //如果前面是1, 现在是3
52             ppre = 2;
53         if ( pre == 2 ) ppre = 2;
54 
55         tmp += find( pos-1, mmod, ppre, lim&&i==bit[pos] );
56     }
57 
58     //注意对有lim的处理(实际上有lim的计算很少)
59     //仔细想想,当lim为true的时候,那么上面的for循环就不完整,也就是num可能不为9
60     //既然该状态不完整,所以不能记忆保存下来啦!
61     if (!lim) dp[pos][mod][pre] = tmp;
62     return tmp;
63 }
64 
65 int solve( int x )
66 {
67     int pos = 0;
68     while(x)
69         { bit[pos++] = x%10; x/=10; }
70 
71     return find(pos-1, 0, 0, true);
72 }
73 
74 int main()
75 {
76     int rhs; 
77     
78     while ( ~scanf("%d", &rhs) )
79     {
80         memset( dp, -1, sizeof(dp) );
81         memset( bit, 0, sizeof(bit) );
82         printf( "%d\n", solve(rhs) ); 
83     }
84     return 0;
85 }
View Code

 

以上是关于数位DP的主要内容,如果未能解决你的问题,请参考以下文章

数位dp小练

动态规划_计数类dp_数位统计dp_状态压缩dp_树形dp_记忆化搜索

数位DP

数位dp

HDU 2089 数位dp入门

数位DP