【数位DP】C~K的幸运数字

本文介绍了一种使用数位动态规划(数位DP)结合记忆化搜索的方法来解决一个特定的问题:计算在指定区间内不含特定组合47的数字的数量。通过详细解释算法思路并给出实现代码,读者可以了解到如何利用数位DP来高效地解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Think:
1知识点:数位DP+记忆化搜索
2思考:
(1):dp数组记录状态应记录[数位][是否已经含有47][前一位数值]
(2):dp数组初始化位置应在总的查询前(所有的dfs搜索之前),进而通过记忆化搜索记录状态,优化时间复杂度
(3):记忆化搜索记录之前已经搜索得到的状态
(4):dfs初始传入的状态

C~K的幸运数字——SDUT题目链接
Time Limit: 1000MS Memory Limit: 65536KB

Problem Description
据说,QAQ 的幸运数字是含有 “47” (4 和 7 相邻)的数,例如 47, 147, 247, 470, 471, 2047 是他的幸运数字,而 74, 1234, 407 就不是他的幸运数字。
而对 C~K 来说,只要不是 QAQ 的幸运数字的数都是他的幸运数字。那么他想问你,在闭区间 [l, r] 中,有多少个自己的幸运数字?

Input
输入数据有多组。第 1 行输入 1 个整数 T (1 <= T <= 10000) 表示数据组数。
对于每组数据,输入 1 行,包含 2 个整数 l, r (1 <= l <= r < 10^9),表示 C~K 要询问的区间。

Output
对于每组数据,在 1 行中输出 1 个整数,表示区间内 C~K 的幸运数字的个数。

Example Input
3
1 1
10 50
1 500

Example Output
1
40
485

Hint

Author
「山东理工大学第一届ACM知识挑战赛(机试)」bLue

以下为Accepted代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int dp[24][2][14], tp, link[24];

int dfs(int pos, bool had_47, int pre, bool is_max);
int solve(int x);

int main(){
    memset(dp, -1, sizeof(dp));
    int T, l, r, ans;
    scanf("%d", &T);
    while(T--){
        scanf("%d %d", &l, &r);
        ans = (r-l+1) - (solve(r)-solve(l-1));
        printf("%d\n", ans);
    }
    return 0;
}
int solve(int x){
    if(!x)
        return 0;
    tp = 0;
    while(x){
        link[tp++] = x%10;
        x /= 10;
    }
    return dfs(tp-1, false, -1, true);
}
int dfs(int pos, bool had_47, int pre, bool is_max){
    if(pos == -1)
        return had_47;
    if(!is_max && dp[pos][had_47][pre] != -1)
        return dp[pos][had_47][pre];
    int up_max = 9;
    if(is_max)
        up_max = link[pos];
    int cnt = 0;
    for(int i = 0; i <= up_max; i++){
        if(pre == 4 && i == 7)
            cnt += dfs(pos-1, true, i, is_max && i == link[pos]);
        else
            cnt += dfs(pos-1, had_47, i, is_max && i == link[pos]);
    }
    if(!is_max)
        dp[pos][had_47][pre] = cnt;
    return cnt;
}


/***************************************************
User name: 
Result: Accepted
Take time: 20ms
Take Memory: 152KB
Submit time: 2017-09-20 21:37:34
****************************************************/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值