- 题目描述
经过了选号和漫长的等待,处女座终于拿到了给小姐姐定制的手环,小姐姐看到以后直呼666!
处女座其实也挺喜欢6这个数字的,实际上他做手环的时候选取的k=6。所以他对于包含数码6的数字极其敏感。每次看到像4567这样的数字的时候他的心就像触电了一样,想起了小姐姐。
现在你要给处女座展示一系列数字,你想知道他的内心会激动多少次。对于同一个数字,他最多只会激动一次,即如果这个数是66666,他还是只会激动一次。- 输入描述:
一行包括两个数字l,r,表示你给处女座展示的数字范围为[l,r]。- 输出描述:
一行一个整数,表示处女座内心激动的次数。- 输入
10 20- 输出
1- 备注:0≤l≤r≤1018
数位dp就是dfs+记忆化数组的过程:
i=4(千位) 0 1 2 3 4 5 6 7 8 9
i=3(百位) 0 1 2 3 4 5 6 7 8 9
i=2(十位) 0 1 2 3 4 5 6 7 8 9
i=1(个位) 0 1 2 3 4 5 6 7 8 9
dfs其实就是模拟数数的过程,我们假设上限是20,dfs的时候我们数到十位的2时,此时2后面的数不用再数了,到个位的时候我们数到0即可(见代码)
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
typedef long long LL;
const int Max_n=100005;
LL dp[20][2];///i表示当前位,j表示上一位是否是6
//dp[i][j]表示当前数位没有6的个数
LL a[20];
//if6上一位是否是6,limit上一位是否是上界
LL dfs(int len,bool if6,bool limit){//没有6的个数
if(len==0) return 1;//枚举到个位
if(!limit&&dp[len][if6]) return dp[len][if6];
//没有到达上限并且当前的数位已经统计过,直接统计已经统计过的即可
LL cnt=0,up=limit?a[len]:9;//上一位是上界,这一位也是上界,否则上界是9
for(int i=0;i<=up;++i){//去数当前位能够数的数(0-9)
if(i==6) continue;//如果当前位是6,剪枝
cnt+=dfs(len-1,i==6,limit&&i==a[len]);//上一位是上限,这一位也是上限,下一位一定只数到上限
//当前位是6说明下一位的上一位是6,(实际这里可以不用记录上一位是否是6(让统计的数只有一位))
}
if(!limit) dp[len][if6]=cnt;//不是上界,直接记录数好的即可
return cnt;
}
LL solve(LL num){
int k=0;//记录有多少数位
while(num){
a[++k]=num%10;
num/=10;
}
return dfs(k,false,true);
}
int main(){
LL l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",r-l+1-solve(r)+solve(l-1)); //我们需要的是有6的个数
return 0;
}