首页 > 代码库 > HDU 3555 数位DP
HDU 3555 数位DP
Bomb Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 6471 Accepted Submission(s): 2250 Problem Description The counter-terrorists found a time bomb in the dust. But this time the terrorists improve on the time bomb. The number sequence of the time bomb counts from 1 to N. If the current number sequence includes the sub-sequence "49", the power of the blast would add one point. Now the counter-terrorist knows the number N. They want to know the final points of the power. Can you help them? Input The first line of input consists of an integer T (1 <= T <= 10000), indicating the number of test cases. For each test case, there will be an integer N (1 <= N <= 2^63-1) as the description. The input terminates by end of file marker. Output For each test case, output an integer indicating the final points of the power. Sample Input 3 1 50 500 Sample Output 0 1 15 Hint From 1 to 500, the numbers that include the sub-sequence "49" are "49","149","249","349","449","490","491","492","493","494","495","496","497","498","499", so the answer is 15.
我的第一个数位DP。。。动态规划真强大,前辈们的思想让我叹服。。由衷的说:佩服!!!
对于这样一类问题:在某个数字区间内求满足条件或不满足条件的数字的个数。 如果问题的数字范围太大的话,一般来说就是数位DP。
数位DP,我的理解就是 假设求的是n---0之间的满足条件的数字的个数,假设n=4891,那么可以这样算:
1)求出3999---0的满足条件数字的个数。
2)求出4799---4000的满足条件数字的个数。
3)求出4889---4800的满足条件数字的个数。
4)求出4891---4890的满足条件数字的个数。
以上加起来就是本题答案。
那么怎么DP呢? 有这样一种思想,如果知道0--k位数字中满足条件的个数num,那么0--k+1位数字中满足条件的个数num1=num*10;因为第k+1位有0--9 10中情况。
以上基本上就是数位dp的思想了。下面解这道题:
题意:给一个数字n,求出0---n之间含有49的数字的个数。
设dp[i][0],dp[i][1],dp[i][2]分别为从0到i位数字之间不含49数字个数,不含49但是最高位(第i位)数字为9的数字的个数,含49的数字的个数。
那么有 dp[i][0]=dp[i-1][0]*10-dp[i-1][1]; //第i位数字可能是4,所以减去i-1位到0中最高位是9的个数。
dp[i][1]=dp[i-1][0];
dp[i][2]=dp[i-1][2]*10+dp[i-1][1]; //第i位数字可能是4,所以加上i-1位到0中最高位是9的个数。
以上就是主要思想,写本题需要注意细节,详见代码:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <iostream> 5 using namespace std; 6 7 main() 8 { 9 __int64 n, dp[33][4], ans; 10 int t, i, j, k, bit[33]; 11 memset(dp,0,sizeof(dp)); 12 dp[0][0]=1; 13 for(i=1;i<=20;i++) //dp过程 14 { 15 dp[i][0]=dp[i-1][0]*10-dp[i-1][1]; 16 dp[i][1]=dp[i-1][0]; 17 dp[i][2]=dp[i-1][2]*10+dp[i-1][1]; 18 } 19 scanf("%d",&t); 20 while(t--) 21 { 22 scanf("%I64d",&n); 23 k=0; 24 n++; //因为该程序求的是[0,n)半开半闭区间的个数,以防数字n满足条件,所以n+1 25 while(n) //把n每位数字放进一个数组里 26 { 27 bit[++k]=n%10; 28 n/=10; 29 } 30 ans=0; 31 bit[k+1]=0; 32 int flag=0; 33 for(i=k;i>=1;i--) //求解过程 34 { 35 ans+=dp[i-1][2]*bit[i]; 36 if(flag) ans+=dp[i-1][0]*bit[i]; //如果高位数字中含有49 那么以后不管是什么数字都满足条件 37 if(!flag&&bit[i]>4) ans+=dp[i-1][1]; //如果高位数字钟不含49 但是第i位大于4,那么需要加上第i位是4,第i+1位是9的数字 38 if(bit[i+1]==4&&bit[i]==9) flag=1; 39 } 40 printf("%I64d\n",ans); 41 } 42 }