HDU ~ 2089 ~ 不要62 (数位DP)

题解

①L~R的符合要求的数字个数,我们可以转化为1~R的符合要求的数字个数 减去 1~(L-1)的美丽数字个数

②定义dp[pos]为选前pos位的方案数。由于要一位一位的去选,dp方程不太好写,所以选择写记忆化搜索。首先需要记录pos(选到了第几位),pre(上一位选的数字),limit(之前的位是否都选到了上限值)。比如327,如果前两位选了32,那么第三位就只能选1~7,如果第一位没选3或第二位没选2,那么第三位就可以选0~9。 

那么有哪些状态是重复的需要记忆化呢,不难想到就是dp[pos位(每一位0~9随便选)]。

 

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000005;
int dp[10];
string num;
int dfs(int pos, int pre, bool limit)
{
    if (pos == -1) return 1;
    if (!limit && pre != 6 && dp[pos] != -1) return dp[pos];
    int E = limit?num[pos]-'0':9, ans = 0;
    for (int i = 0; i <= E; i++)
    {
        if (i == 4 || pre == 6 && i == 2) continue;
        ans += dfs(pos-1, i, limit&&i == E);
    }
    if (!limit && pre != 6) dp[pos] = ans;
    return ans;
}
int solve(int x)
{
    num = to_string(x); reverse(num.begin(), num.end());
    return dfs(num.size()-1, 0, 1);
}
int main()
{
    memset(dp, -1, sizeof(dp));
    int L, R;
    while (~scanf("%d%d", &L, &R) && (L+R))
    {
        printf("%d\n",  solve(R) - solve(L-1));
    }
    return 0;
}
/*
1 100
0 0
*/

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值