HDU-3555 Bomb(数位dp+模板)

点击这里送你去杭电做一些让你bomb的题目

Bomb

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

 

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题,做了这道题之后我的人生历程就变了,原来还有这种烧脑的玩意~_~,本文的思路完全来自于大佬的blog  我先膜拜一下  Orz↓↓↓

→→→点击参照更详细的大佬的解释 Orz←←←

我就先把数位dp的模板罗列一下

先驱条件:

ll solve(ll x){
	memset(dp,-1,sizeof(dp));//不要忘了初始化dp数组
	ll cnt=0;	
	while(x){//将数字逐个存到数组里面
		a[cnt++]=x%10;
		x/=10;
	}
	return dfs(cnt-1,xx,xx,limit);
}

核心dfs:

ll dfs(ll pos,ll pre,bool limit){//pos是当前位置,pre为上一位数,limit为限制标志 
	//limit为真,则当前位最大值受限,else不 
	
	if(pos==-1)return 1;//到头了 找到一个符合条件的数 
	if(!limit&&dp[pos][pre]!=-1)//已经搜索过了,直接使用之前的结果  
		return dp[pos][pre]; //!!!必要的剪枝 不然直接 TLE TLE TLE
	
	ll up=limit?a[pos]:9;  上限根据具体的题目来设定~~~
	 
	ll ans=0;
	for(ll i=0;i<=up;i++){//下面是枚举  根据具体题目变换
	    if(,,,)
			ans+=dfs(pos-1,i,limit&&i==a[pos]);
        。。。 
        }
	if(!limit)
		dp[pos][pre]=ans;//本次搜索完成,更新dp数组 
		
	return ans;
}

数位dp的模式很固定,唯独dfs的参数,上限和if条件里的dfs操作,需要根据题目来改变

这道题让我们求1-给出的数n 中含有‘49’的所有数的个数,那我们就求出所有的数中不含有49的个数然后再减去求得的ans

关于本道题目的dp数组的含义:
pos表示当前遍历的是第几位,pre表示前一位是几
dp[pos][pre]记录了遍历第pos为位时,前一位为pre时的状态数

下面是AC代码,如果有不明白的地方请点击上方的链接,真的是非常详细,我就不在关公面前耍大刀了   Orz 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#define ll long long
using namespace std;
const ll inf=0x3f3f3f3f;
const ll mm=50;

ll dp[mm][15];//dp[pos][pre]表示pos位数,前导为pre的不含49的数字个数 
ll a[mm];
ll t,n;

ll dfs(ll pos,ll pre,bool limit){//pos是当前位置,pre为上一位数,limit为限制标志 
	//limit为真,则当前位最大值受限,else不 
	
	if(pos==-1)return 1;//到头了 找到一个没有49的数 
	if(!limit&&dp[pos][pre]!=-1)//已经搜索过了,直接使用之前的结果  
		return dp[pos][pre]; //!!!必要的剪枝 不然直接 TLE TLE TLE
	
	//ll up=limit?a[pos]:9; 
	ll up;//神奇的玩意,确定当前数的最大值  
	if(limit)up=a[pos];//受限制 ,为所给数的当前为max 
	else up=9;//else 范围 0~9 
	 
	ll ans=0;
	for(ll i=0;i<=up;i++)
		if(pre==4&&i==9)
			continue;//碰到了49  越过 
		else//深入到下一位 
			ans+=dfs(pos-1,i,limit&&i==a[pos]);//上一位为最大 也未必受限制,需要 && 一下 
		 								    //比如5752,现在到了47xx,第三位并不受限制  
	if(!limit)
		dp[pos][pre]=ans;//本次搜索完成,更新dp数组 
		
	return ans;
}

int main()
{
	cin>>t;
	while(t--){
		memset(dp,-1,sizeof(dp));
		cin>>n;
		ll len=0;
		ll nn=n;//备份  
		while(n){//将数字存入数组  
			a[len++]=n%10;
			n/=10;
		}
		ll temp=dfs(len-1,0,1);//这是不含有‘49’的个数 
		ll res=nn-temp+1;//result 
		cout<<res<<endl;
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值