您的位置:首页 > 其它

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

2013-10-09 09:19 639 查看


hdu3555 Bomb

2012-07-12 19:37 372人阅读 评论(1) 收藏 举报

integerinputoutputtrainingnumberseach


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

HintFrom 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
plaincopy

#include <stdio.h>

#include <string.h>

#include <algorithm>

using namespace std;

int dig[20];

long long dp[20][2][12];

long long F(int pos,bool have,int last,bool inf)

{

int i;

if (pos==-1) return have;

if (!inf && dp[pos][have][last]!=-1) return dp[pos][have][last];

int end=inf?dig[pos]:9;

long long ans=0;

for (i=0;i<=end;i++)

{

if (last==4 && i==9) ans+=F(pos-1,true,i,inf && (i==end));

else ans+=F(pos-1,have,i,inf && (i==end));

}

if (!inf)

{

dp[pos][have][last]=ans;

}

return ans;

}

long long Cal(long long t)

{

int i,j,pos=0;

while(t)

{

dig[pos++]=t%10;

t/=10;

}

return F(pos-1,0,0,1);

}

int main()

{

int i,j,T;

__int64 n;

scanf("%d",&T);

while(T--)

{

memset(dp,-1,sizeof(dp));

scanf("%I64d",&n);

printf("%I64d\n",Cal(n));

}

return 0;

}


HDU 3555 Bomb (数位DP)

分类: HDU 动态规划DP2012-08-14
20:24 466人阅读 评论(1) 收藏 举报

做的第一道数位DP啊!开始在找规律,搜索,做了很久终于找到了规律,上网一查发现原来这样的叫数位DP。。


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

[cpp] view
plaincopy

//Time:15MS

//Memory:488K

#include<string.h>

#include<stdio.h>

long long dp[20][3];

int num[20];

int main()

{

memset(dp,0,sizeof(dp));

dp[0][0] = 1;

for(int i = 1;i<= 20;i++){

dp[i][0]=dp[i-1][0]*10-dp[i-1][1]; //dp[i][0] 表示i位数字中不含49的数字的个数

dp[i][1]=dp[i-1][0]; //dp[i][1] 表示i位数字中以9开头的数字的个数

dp[i][2]=dp[i-1][2]*10+dp[i-1][1];//dp[i][2] 表示i位数字中含有49的数字的个数

}

int t;

scanf("%d",&t);

while(t--)

{

int len = 0,last = 0;

long long ans = 0;

long long n = 0;

scanf("%I64d",&n);

n++;

memset(num,0,sizeof(num));

while(n){

num[++len]=n%10;

n/=10;

}

bool flag=false;

for(int i=len;i>=1;i--)

{

ans+=dp[i-1][2]*num[i];

if(flag)

{

ans+=dp[i-1][0]*num[i];

}

if(!flag && num[i]>4)

{

ans+=dp[i-1][1];

}

if(last==4 && num[i]==9)

{

flag=true;

}

last=num[i];

}

printf("%I64d\n",ans);

}

}


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

分类: 动态规划2013-10-08
16:34 80人阅读 评论(0) 收藏 举报

数位DP

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

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

[cpp] view
plaincopyprint?

//dp[len][0]表示长度为len不含49的数量

//dp[len][1]表示长度为len不含44但以9开头的数字的数量

//dp[len][2]表示长度为len含有49的数量

#include<stdio.h>

#include<string.h>

__int64 dp[20][3];

int num[20];

int main(){

dp[0][0]=1;

for(int i=1;i<=20;i++){

dp[i][0]=dp[i-1][0]*10-dp[i-1][1];//要减去9开头的数

dp[i][1]=dp[i-1][0];//在不含49的数量中加9在开头

dp[i][2]=dp[i-1][2]*10+dp[i-1][1];//以前含49、这一位有10种选择+以前只含9这一位可以是4

}

int t;

scanf("%d",&t);

while(t--){

int len=1,last=0;

__int64 ans=0,n=0;

scanf("%I64d",&n);

memset(num,0,sizeof(num));

n++;

while(n>0){//用num数组来记录每一位的数字、为下面递推做准备

num[len]=n%10;

n/=10;

len++;

}

int flag=0;

for(int i=len;i>=1;i--){//从高位往低位递推

ans+=dp[i-1][2]*num[i];//如果后面含有49、那么这一位可以填1到(num[i]-1)

if(flag==1)//如果前一位挨着49

ans+=dp[i-1][0]*num[i];//那么加上这个是没问题的

if(flag==0&&num[i]>4)//如果前一位没有挨着49、但是这一位比4大

ans+=dp[i-1][1];//那么加上开头为9的是正确的、

if(last==4&&num[i]==9)//判断当前位和上一位是否能组成49

flag=1;

last=num[i];//当前位转移为上一位

}

printf("%I64d\n",ans);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: