题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555
题目大意:如果某个数中含有49,那就叫2B数(原来好像不是这个,随便啦).问[0,n]里有几个2B数,n <=2^63 - 1
解题思路:数位DP,和Hdu 3652差不多,但我感觉这题更简单,因为记录的状态更少。这题我用两种方法写过了,其实说两种方法也就是记忆化搜索时传递的参数不一样,核心都是一样的。
第一种:传递三个参数,pos,flag,limit,pos表示当前转移到第几位,flag有三个值(2,1,0)对应着(含有49,不含49但前位是4,前位不是4也不含49),limit表示是否有上限,比如n=1234,现在转移到12,如果下一位选3,那么再下一位就有上限,上限为4,如果不选3,那么下一位就没限制,最高位9,转移能保证转移到数比n小。这样dp数组时2维的。
第二种:这种跑的略慢,但更好理解。传递四个参数,pos,pre,flag,limit,pos和flag的意义一样,pre表示前一位是什么,flag表示是否含49,转移dp数组时3维的。
测试数据:
4
1
50
500
代码:
//第一种写法 #include <stdio.h> #include <string.h> #define MAX 1100 #define int64 __int64 int64 digit[30]; int64 dp[30][3],n; int64 Dfs(int pos,int flag,int limit) { if (pos == -1) return flag == 2; if (!limit && dp[pos][flag] != -1) return dp[pos][flag]; int64 sum = 0; int end = limit ? digit[pos] : 9; for (int i = 0; i <= end; ++i) { int have = flag; //flag == 2 || (flag == 1 && i == 4) if (flag == 1 && i == 9) have = 2; if (flag == 0 && i == 4) have = 1; if (flag == 1 && i != 4 && i != 9) have = 0; //printf("pos %d flag %d have %d i %d sum %d\n",pos,flag,have,i,sum); sum += Dfs(pos-1,have,limit&&i==end); } if (!limit) dp[pos][flag] = sum; return sum; } int64 Cal(int64 n) { int pos = 0; while (n > 0) { digit[pos] = n % 10; n /= 10,pos++; } return Dfs(pos-1,0,1); } int main() { int i,j,k,t; scanf("%d",&t); while (t--) { scanf("%I64d",&n); memset(dp,-1,sizeof(dp)); printf("%I64d\n",Cal(n)); } }
//第二种写法 #include <stdio.h> #include <string.h> #define MAX 1100 #define int64 __int64 int64 digit[30]; int64 dp[30][10][3],n; int64 Dfs(int pos,int pre,int flag,int limit) { if (pos == -1) return flag == 1; if (!limit && dp[pos][pre][flag] != -1) return dp[pos][pre][flag]; int64 sum = 0; int end = limit ? digit[pos] : 9; for (int i = 0; i <= end; ++i) { if (pre == 4 && i == 9) sum += Dfs(pos-1,i,1,limit && end == i); else sum += Dfs(pos-1,i,flag,limit && end == i); } if (!limit) dp[pos][pre][flag] = sum; return sum; } int64 Cal(int64 n) { int pos = 0; while (n > 0) { digit[pos] = n % 10; n /= 10,pos++; } //printf("%d\n",pos); int64 ans = Dfs(pos-1,-1,0,1); return ans; } int main() { int i,j,k,t; scanf("%d",&t); while (t--) { scanf("%I64d",&n); memset(dp,-1,sizeof(dp)); printf("%I64d\n",Cal(n)); } }