题目大意
给定区间[L,R],统计区间内不含62(连在一起)或4的数的个数。
分析
数位Dp。所谓数位Dp,就是一种优化平常数数的方式,而平常数数,则是一种Dfs的过程,所以数位Dp就是Dfs+记忆化搜索。在搜索过程中,需要传3个量,(len,if6,limit),len表示当前的数位,if6表示上一位是否为6,limit表示上一位是否到了最高位。对于每一位上的枚举,上界为:若上一位到了最高位,则这一位上界也只能到这一位的最大值,否则就是9(数位最大为9),下界就是从0开始;对于递归的下界,若len=0,即到了个位,则找到一个,所以返回1;对于题目要求,若当前枚举到2且上一位是6,或枚举到4,直接continue;这样就统计了0~n的符合题意的数的个数,记为solve(n),则答案为solve(R)-solve(L-1)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int digit[20];
LL f[20][2];
LL dfs(int len,bool if6,bool limit) {
if (len==0) return 1;
if (!limit&&f[len][if6]) return f[len][if6];
LL cnt=0;
int up_bound=(limit?digit[len]:9);
for (int i=0;i<=up_bound;i++) {
if (if6&&i==2)
continue;
if (i==4) continue;
cnt+=dfs(len-1,i==6,limit&&i==up_bound);
}
if (!limit) f[len][if6]=cnt;
return cnt;
}
LL solve(LL num) {
int k=0;
memset(f,0,sizeof(f));
while (num) {
digit[++k]=num%10;
num/=10;
}
return dfs(k,false,true);
}
int main() {
LL n,m;
while (~scanf("%lld%lld",&n,&m)&&n+m) {
printf("%lld\n",solve(m)-solve(n-1));
}
return 0;
}