关于此题[ABC 387]C - Snake Numbers 数位DP的一些总结

传送门
这道题要求我们求[l,r]范围内所有的“蛇数”,即这个数的第一位严格大于它的其他位的数。
看到数据范围并且发现答案区间可加减性联想到数位DP。其实有点类似模板题,与经典的数位DP题类似的,我们需要判断前导0,需要判断当前枚举的数是否是贴着所给的数,在此题中如果想要记忆化的话,还需要加两个量,即d表示当前枚举的数首位是什么,还有st表示当前枚举的数首位在什么位置,这两个是为了dp数组记忆化服务,若是没有这两个的话dp数组就没办法精确地记录各种情况的答案。
代码:

#include<bits/stdc++.h>

using namespace std;

long long t;
const long long N = 2e5 + 10;
long long l,r;
long long dp[20][20][20][20];
vector<long long> digit;

long long dfs(long long pos,long long statu,long long d,long long lead,long long done,long long st) {
                                            //pos:当前从高到低枚举到的位置,statu:上一个数是多少(其实可要可不要),d:当前枚举的数首位是多少,lead:当前是否是前导0,done:当前枚举的数是否贴着所给的数,st:当前枚举的数第一位是什么
    if(pos == -1) return 1;
    if(!lead && !done && ~dp[pos][statu][st][d] && d) return dp[pos][statu][st][d];
    long long res = 0,end = done ? digit[pos] : 9;
    for(long long i = 0;i <= end;i++) {
        if(d && i >= d) continue;
        bool flag = (lead && !i);
        long long tmp,ss;
        if(lead && flag) tmp = 0,ss = 0;
        else if(lead && !flag) tmp = i,ss = pos;
        else tmp = d,ss = st;
        res += dfs(pos-1,i,tmp,flag,done && i == end,ss);
    }
    if(!done && !lead) dp[pos][statu][st][d] = res;
    return res;
}

long long work(long long k) {
    memset(dp,-1,sizeof dp);
    digit.clear();
    while(k) {
        digit.push_back(k % 10);
        k /= 10;
    }
    return dfs(digit.size()-1,0,0,1,1,0);
}

void solve() {
    cin >> l >> r;
    cout << work(r) - work(l-1);
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    t = 1;
    while(t--) solve();

    return 0;
}
posted @   孤枕  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
我命令你,喜欢我!