hdu 2089 不要62

描述

在这里插入图片描述

题解

以1-100为例,函数递归调用过程如下图:
在这里插入图片描述
需要注意的两点是:
1)为什么需要将dp设置成dp[20][2]这样大小的数组。(需要区分上一个数位是否取值6这两种情况)
以上图为例:
假设将数组dp设置成dp[20],
当百位为0,十位为0时,毋庸置疑,dp[0]为9。
当百位为0,十位为6时,由于dp[0]状态已有了,此时程序直接返回dp[0],显然这是错误的。
所以我们加上第二维,来标志上一位是否为6。为6,将第二维置为1;不为6。将第二维置为0。
2)记忆化搜索时,为什么需要加上 if(!limit)这个判断条件
同样以上图为例
当百位为0时,毋庸置疑,dp[1][0]为79,
当百位为1时,此时limit为true,如若没有(!limit)这个条件,由于dp[1][0]这个状态已经有了,程序直接返回dp[1][0],显然这是错误的。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
typedef long long ll;
int a[20];
int dp[20][2];
/**
dfs(pos-1,-1,0,true)
pos-1:当前所枚举的数位
pre:前一个数位
sta:表示当前数位的前一位是否为6;为6还是不为6 这两种情况需要分开来登记
limit:当前所枚举的pos-1是否是最高位
**/
int dfs(int pos,int pre,int sta,bool limit)
{
    if(pos==-1) return 1;
    ///记忆化搜索,(需要保证limit取值为false,也就是当前取值不受到数字大小的限制)
    if(!limit && dp[pos][sta]!=-1) return dp[pos][sta];
    ///根据limit的取值获取下一位的取值上限
    int up=limit ? a[pos] : 9;
    int tmp=0;
    for(int i=0;i<=up;i++)
    {
        ///和sta结合起来考虑,如果sta取值为1,则这个条件必然会有触发的时候
        if(pre==6 && i==2)continue;
        if(i==4) continue;//都是保证枚举合法性
        /**
        下面参数第四项为limit && i==a[pos],而不是!limit
        因为如果枚举最高位最大一个数字,
        那么下一位的枚举上界也会受到限制
        */
        tmp+=dfs(pos-1,i,i==6,limit && i==a[pos]);
    }
    if(!limit) dp[pos][sta]=tmp;
    return tmp;
}
int solve(int x)
{
    ///获取最高位存储在pos中,并将每一位的数字存储在数组a中
    int pos=0;
    while(x)
    {
        a[pos++]=x%10;
        x/=10;
    }
    return dfs(pos-1,-1,0,true);
}
int main()
{
    int le,ri;
    //memset(dp,-1,sizeof dp);可优化
    while(~scanf("%d%d",&le,&ri) && le+ri)
    {
        memset(dp,-1,sizeof dp);
        printf("%d\n",solve(ri)-solve(le-1));
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值