题目描述
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?
输入格式
输出格式
For each test case, output an integer indicating the final points of the power.
翻译:给出n,问1~n中有多少个数中含有49.
A掉的第一道数位dp题。为了方便(其实是另外一个OJ的翻译),我们把带有49的数叫做幸运数。设dp(i,0)表示长度为i的幸运数个数,其中这些数不以49开头。dp(i,1)就是以49开头的情况。然后记搜即可。具体细节在代码里标明:
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 21
using namespace std;
int N[maxn];
long long dp[maxn][2];
long long dfs(int len,bool is4,bool havelim){//havelim : have limitation
if(len==0) return 1;//搜索范围为1~tmp
if(!havelim&&dp[len][is4]) return dp[len][is4];//只有没有限制时才可以记忆化。为什么?因为记的就是没有限制的情况......
int lim=havelim?N[len]:9;//如果上一位填满了限制,那么这一位也必须有限制
long long cnt=0;//有多少个不是幸运数的数
for(register int i=0;i<=lim;i++){
if(is4&&i==9) continue;//排除幸运数的情况
cnt+=dfs(len-1,i==4,havelim&&i==lim);//只有上一位有限制并且这一位达到限制时下一位才能有限制
}
return havelim?cnt:dp[len][is4]=cnt;//没有限制时记忆化
}
int main(){
int t;cin>>t;
while(t--){
memset(N,0,sizeof N);
memset(dp,0,sizeof dp);
unsigned long long n,tmp; cin>>n; tmp=n; int k=0;
while(tmp) N[++k]=tmp%10,tmp/=10;//得到n的位数
printf("%lld\n",n-dfs(k,false,true)+1);//得到“非幸运数”个数应该比得到“幸运数”个数要容易实现
}
return 0;
}