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 }