HDU 3555 Bomb

Bomb

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)

Total Submission(s): 3338    Accepted Submission(s): 1177

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问题,寻找含有49的数字,可以用递推和DFS两种方法写
本题代码稍加修改即可适用于各种有附加条件的数位DP题
 
递推法:
 
[C++]
 1 #include<iostream>
 2 #include<cstdio>
 3 
 4 using namespace std;
 5 
 6 //d0[i]存放位数为i的不含49的数字个数
 7 //d1[i]存放位数为i,不含49但最前面一位是9的数字个数
 8 //d2[i]存放位数为i的包含49的数字个数
 9 long long d0[20],d1[20],d2[20];
10 unsigned long long n;
11 
12 //初始化
13 void initial()
14 {
15     long long j=1;
16     d0[0]=1;
17     for(int i=1;i<=19;i++)
18     {
19         j*=10;
20         d2[i]=d2[i-1]*10+d1[i-1];
21         d1[i]=d0[i-1];
22         d0[i]=j-d2[i];
23     }
24 }
25 
26 int main()
27 {
28     int t;
29     cin>>t;
30     initial();
31     while(t--)
32     {
33         int top=0;
34         int num[20];
35         bool flag=false;
36         unsigned long long ans=0;
37         cin>>n;
38         n++;
39         while(n)
40         {
41             num[++top]=n%10;
42             n/=10;
43         }
44         num[top+1]=0;
45         for(int i=top;i;i--)
46         {
47             for(int j=0;j<num[i];j++)
48             {
49                 ans+=d2[i-1];
50                 if(flag)
51                     ans+=d0[i-1];
52                 if((!flag)&&j==4)
53                     ans+=d1[i-1];
54             }
55             if(num[i+1]==4&&num[i]==9)
56                 flag=true;
57         }
58         printf("%I64d\n",ans);
59     }
60 
61     return 0;
62 }

 

DFS法(个人认为这种方法比较通用):

 

[C]
 1 #include<stdio.h>
 2 #include<string.h>
 3 
 4 int num[20];
 5 long long n;
 6 //dp[i][j]表示计算到第i位时,状态为j的数的个数
 7 //j=0表示之前不含49且该位不是9,j=1表示之前不含49但该位是4,j=2表示之前已经包含49
 8 long long dp[20][3];
 9 
10 //dfs函数:pos为当前所处的位,flag记录状态(即dp数组的第二维),limit表示前一位是否达到了其最大值,若达到则后面的一位的上限会有限制
11 unsigned long long dfs(int pos,int flag,int limit)
12 {
13     int end,i,have;
14     unsigned long long sum=0;
15     if(pos==-1)
16         return flag==2;
17     if((!limit)&&(dp[pos][flag]!=-1))
18         return dp[pos][flag];
19 
20     end=limit?num[pos]:9;
21     for(i=0;i<=end;i++)
22     {  
23         have=flag;
24         if(flag==1&&i==9)
25             have=2;
26         if(flag==0&&i==4)
27             have=1;
28         if(flag==1&&i!=4&&i!=9)
29             have=0;
30         sum+=dfs(pos-1,have,limit&&i==end);
31     }
32     if(!limit)
33         return dp[pos][flag]=sum;
34     return sum;
35 }
36 
37 //col()函数,将待处理的大整数按位分解存入num数组中
38 unsigned long long col()
39 {
40     int pos=0;
41     while(n)
42     {
43         num[pos++]=n%10;
44         n/=10;
45     }
46     return dfs(pos-1,0,1);
47 }
48 
49 int main()
50 {
51     int t;
52     scanf("%d",&t); 
53 
54     while(t--)
55     {
56         scanf("%I64d",&n);  
57         memset(dp,-1,sizeof(dp));
58         printf("%I64d\n",col());
59     }
60     return 0;
61 }

 

 

posted @ 2013-04-30 08:22  ~~Snail~~  阅读(241)  评论(0)    收藏  举报