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.
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 }


浙公网安备 33010602011771号