动态规划晋级——HDU 3555 Bomb【数位DP详解】

 

hdu3555 Bomb

  372人阅读  评论(1)  收藏  举报
integer input output training numbers each

Bomb

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 1604    Accepted Submission(s): 592


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.
 

Author
fatboy_cw@WHU
 

Source
2010 ACM-ICPC Multi-University Training Contest(12)——Host by WHU
 

Recommend
zhouzeyong


顺便写道数位dp的题,直接dfs下去就可以了,没什么说的。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <algorithm>  
  4. using namespace std;  
  5.   
  6. int dig[20];  
  7. long long dp[20][2][12];  
  8.   
  9. long long F(int pos,bool have,int last,bool inf)  
  10. {  
  11.     int i;  
  12.     if (pos==-1) return have;  
  13.     if (!inf && dp[pos][have][last]!=-1) return dp[pos][have][last];  
  14.     int end=inf?dig[pos]:9;  
  15.     long long ans=0;  
  16.     for (i=0;i<=end;i++)  
  17.     {  
  18.         if (last==4 && i==9) ans+=F(pos-1,true,i,inf && (i==end));  
  19.         else ans+=F(pos-1,have,i,inf && (i==end));  
  20.     }  
  21.     if (!inf)  
  22.     {  
  23.         dp[pos][have][last]=ans;  
  24.     }  
  25.     return ans;  
  26. }  
  27.   
  28. long long Cal(long long t)  
  29. {  
  30.     int i,j,pos=0;  
  31.     while(t)  
  32.     {  
  33.         dig[pos++]=t%10;  
  34.         t/=10;  
  35.     }  
  36.     return F(pos-1,0,0,1);  
  37.   
  38. }  
  39.   
  40. int main()  
  41. {  
  42.     int i,j,T;  
  43.     __int64 n;  
  44.     scanf("%d",&T);  
  45.     while(T--)  
  46.     {  
  47.         memset(dp,-1,sizeof(dp));  
  48.         scanf("%I64d",&n);  
  49.         printf("%I64d\n",Cal(n));  
  50.     }  
  51.     return 0;  
  52. }  
 

HDU 3555 Bomb (数位DP)

分类: HDU 动态规划DP   466人阅读  评论(1)  收藏  举报

做的第一道数位DP啊!开始在找规律,搜索,做了很久终于找到了规律,上网一查发现原来这样的叫数位DP。。动态规划晋级——HDU 3555 Bomb【数位DP详解】_第1张图片

找到的规律就是这个样子了。有了规律就很好做了。dp[i][0]=dp[i-1][0]*10-dp[i-1][1];是因为要减去49XXX的情况。

[cpp]  view plain copy
  1. //Time:15MS   
  2. //Memory:488K  
  3. #include<string.h>  
  4. #include<stdio.h>  
  5. long long dp[20][3];  
  6. int num[20];  
  7. int main()  
  8. {  
  9.     memset(dp,0,sizeof(dp));  
  10.     dp[0][0] = 1;  
  11.     for(int i = 1;i<= 20;i++){  
  12.         dp[i][0]=dp[i-1][0]*10-dp[i-1][1]; //dp[i][0] 表示i位数字中不含49的数字的个数  
  13.         dp[i][1]=dp[i-1][0];               //dp[i][1] 表示i位数字中以9开头的数字的个数  
  14.         dp[i][2]=dp[i-1][2]*10+dp[i-1][1];//dp[i][2] 表示i位数字中含有49的数字的个数  
  15.     }  
  16.     int t;  
  17.     scanf("%d",&t);  
  18.     while(t--)  
  19.     {  
  20.         int len = 0,last = 0;  
  21.         long long ans = 0;  
  22.         long long n = 0;  
  23.         scanf("%I64d",&n);  
  24.         n++;  
  25.         memset(num,0,sizeof(num));  
  26.         while(n){  
  27.             num[++len]=n%10;  
  28.             n/=10;  
  29.         }  
  30.         bool flag=false;  
  31.         for(int i=len;i>=1;i--)  
  32.         {  
  33.             ans+=dp[i-1][2]*num[i];  
  34.             if(flag)  
  35.             {  
  36.                 ans+=dp[i-1][0]*num[i];  
  37.             }  
  38.             if(!flag && num[i]>4)  
  39.             {  
  40.                 ans+=dp[i-1][1];  
  41.             }  
  42.             if(last==4 && num[i]==9)  
  43.             {  
  44.                 flag=true;  
  45.             }  
  46.             last=num[i];  
  47.         }  
  48.         printf("%I64d\n",ans);  
  49.     }  
  50. }  

动态规划晋级——HDU 3555 Bomb【数位DP详解】

分类: 动态规划   80人阅读  评论(0)  收藏  举报
数位DP

转载请注明出处:http://blog.csdn.net/a1dark

分析:初学数位DP完全搞不懂、很多时候都是自己花大量时间去找规律、记得上次网络赛有道数位DP、硬是找规律给A了、那时候完全不知数位DP为何物、不过还是有很多时候要用数位DP、比如当一个数字超过了数组承受的极限、不能再打表AC、先看这道题、首先划分状态、然后初始化、最后从高位向低位状态转移、代码含详解

[cpp]  view plain copy print ?
  1. //dp[len][0]表示长度为len不含49的数量  
  2. //dp[len][1]表示长度为len不含44但以9开头的数字的数量  
  3. //dp[len][2]表示长度为len含有49的数量  
  4. #include<stdio.h>  
  5. #include<string.h>  
  6. __int64 dp[20][3];  
  7. int num[20];  
  8. int main(){  
  9.     dp[0][0]=1;  
  10.     for(int i=1;i<=20;i++){  
  11.         dp[i][0]=dp[i-1][0]*10-dp[i-1][1];//要减去9开头的数  
  12.         dp[i][1]=dp[i-1][0];//在不含49的数量中加9在开头  
  13.         dp[i][2]=dp[i-1][2]*10+dp[i-1][1];//以前含49、这一位有10种选择+以前只含9这一位可以是4  
  14.     }  
  15.     int t;  
  16.     scanf("%d",&t);  
  17.     while(t--){  
  18.         int len=1,last=0;  
  19.         __int64 ans=0,n=0;  
  20.         scanf("%I64d",&n);  
  21.         memset(num,0,sizeof(num));  
  22.         n++;  
  23.         while(n>0){//用num数组来记录每一位的数字、为下面递推做准备  
  24.             num[len]=n%10;  
  25.             n/=10;  
  26.             len++;  
  27.         }  
  28.         int flag=0;  
  29.         for(int i=len;i>=1;i--){//从高位往低位递推  
  30.             ans+=dp[i-1][2]*num[i];//如果后面含有49、那么这一位可以填1到(num[i]-1)  
  31.             if(flag==1)//如果前一位挨着49  
  32.                 ans+=dp[i-1][0]*num[i];//那么加上这个是没问题的  
  33.             if(flag==0&&num[i]>4)//如果前一位没有挨着49、但是这一位比4大  
  34.                 ans+=dp[i-1][1];//那么加上开头为9的是正确的、  
  35.             if(last==4&&num[i]==9)//判断当前位和上一位是否能组成49  
  36.                 flag=1;  
  37.             last=num[i];//当前位转移为上一位  
  38.         }  
  39.         printf("%I64d\n",ans);  
  40.     }  
  41.     return 0;  
  42. }  



你可能感兴趣的:(动态规划,HDU,动态规划DP)