FZU2109(数位DP)

题目的意思就是给出一个范围.问这个范围内有几个数  满足奇数位上的数,都比左右两边大.

我们要一位位判断,直到整个数结束.

我们拿0-34567这个范围来举例.

这里有两个不好理解的标志位.

首先我们要考虑的是前导0问题.(也就是最开始会出现很多不必要的0 ,因为564是符合条件的,但是我们表示时是00564 ,直到5这一位才算是开始了,所以5才是第0位)

首先我们要有个标志位,标记前面是不是全是前导0, 如果前面全是,并且我们要算的这一位还是0,那么接下去就还是按全是前导0来算.

只要出现一位不是0了,那就永远不是前导0,就算填的是0,它也不是前导0;

还有一个标志就是 前面几位是不是达到最大值..比如你第一位是3 ,第二位是4 ,那么第三位只能选择填充0到5 ,如果再大,就超过最大值了.但是如果你前面没有达到最大.前两位填了33那么接下去所有位数,都可以填到9,也不会超过最大值.       那么判断接下去是不是还有达到最大,要满足两个,第一前面达到最大,并且当前填充的这个数字仍然是最大.


解决了这两个标志位,就可以开始dp了.

如果这一位是奇数位,且填的数大于前面,就可以继续.或者这一位是偶数位,且填的数小于前面.

知道所有位数填充完了,返回成功了一个,最后计算成功了几个.

但如果直接不断递归,会超时.所以我们利用dp的记忆化搜索.

d[pos][num][odd]   pos代表当前是第几位了,num代表前一个数字是几,odd代表是奇数还是偶数..

首先你只到当前是第几位,也就是知道还剩下多少位要填,知道num,就知道当前要填数要和那个数字比较,当然还有奇偶行.

那是不是当这三个条件固定了,那么在这种情况下有几种可能是不是也固定了?

不一定,因为如果前面的值没打到最大,那么当前这位可以填0-9,那么没问题.

但是如果前面已经达到最大值了..那么当前这位就不能填0-9了,而是填0到这个数的最大值.

那么就不是唯一确定的值,就不能记忆化搜索(结果可能和你记录的不一样.)

为了避免.我们就只在前面没有达到最大值时,才采用记忆化搜索.



AC代码:


#include<stdio.h>
#include<string.h>
int d[12][12][2];
int diet[12];
int dfs(int  pos , int pre0 , int isodd , int num , int s) {
	if(pos == -1)
		return 1;
	if(!s && d[pos][num][isodd] != -1)
		return d[pos][num][isodd];
	int upper = s ? diet[pos] : 9;
	int ans = 0;
	for (int i = 0 ; i <= upper ; i++) {
		if (i == 0 && pre0) {
			ans += dfs(pos - 1 , 1 ,isodd , 9 , 0);
		}
		else if(isodd && i <= num)
			ans += dfs(pos - 1 , 0 , isodd ^ 1 , i , s && (i == upper));
		else if(!isodd && i >= num)
			ans += dfs(pos - 1 , 0 , isodd ^ 1 , i , s && (i == upper));
	}
	if(!s)
		d[pos][num][isodd] = ans;
	return ans;
}
int cul(int x) {
	int pos = 0;
	while(x) {
		diet[pos++] = x % 10;
		x /= 10;
	}
	return dfs(pos - 1 , 1 , 1 , 9 , 1);
}
int main () {
	int t ; 
	int l,r;
	scanf("%d",&t);
	memset(d , -1 ,sizeof(d));
	while(t--) {
		scanf("%d%d",&l,&r);
		printf("%d\n",cul(r) - cul(l - 1));
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值