概述
点击这里送你去杭电做一些让你bomb的题目
BombTime 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.
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.
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;
}
最后
以上就是和谐小伙为你收集整理的HDU-3555 Bomb(数位dp+模板)Bomb→→→点击参照更详细的大佬的解释 Orz←←←的全部内容,希望文章能够帮你解决HDU-3555 Bomb(数位dp+模板)Bomb→→→点击参照更详细的大佬的解释 Orz←←←所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复