数位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 }
萌新第二题: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 }
以上是关于数位DP的主要内容,如果未能解决你的问题,请参考以下文章