「HDU2089」 不要62 - 数位Dp

题目大意

给定区间[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;
}

猜你喜欢

转载自blog.csdn.net/sin_Yang/article/details/82390622
今日推荐