关于此题P4124 [CQOI2016] 手机号码 [数位DP]的一些总结

传送门
数位DP都长这样吗(bushi
记忆化的维数一定得是能完全确定当前所在状态的,如果当前所在状态不能够由记忆化的各个维度共同确定的,即同一各个维度的值可能对应多个对答案有着不同贡献的状态的话,这个记忆化就会出问题(就相当于DP的维数并不能完整反应转移过程的各个状态一样

就拿这道题举例,在我的写法中,枚举到当前位时,需要六个量来完全确定当前状态,当前所在位数、目前为止是否出现4、目前为止是否出现8、前面枚举的所有位数当中出现连续相同数字最多多少次、上一位数是多少,以及包含当前位的出现连续相同数字多少个,漏一个都无法完整确定当前状态。

然而比如说这道题:P4999 烦人的数学作业,我们DP数组的状态只需两维,分别是当前所在位以及在此之前枚举的所有数的和,这就足够完全确定当前所在状态了,因为在此之前枚举的所有数的和如果都是sum的话,那么不管其各个位具体数字是多少,它们对答案的贡献都是相同的。

#include<bits/stdc++.h>
    
using namespace std;
    
long long t;
long long l,r;
long long dp[20][2][2][20][10][20];
vector<long long> digit;

long long dfs(long long pos,long long cot,bool v1,bool v2,bool done,long long nct,long long status,bool lead) {
    if(pos < 0) {
        if(cot >= 3 && (!v1 || !v2)) return 1;
        else return 0;
    }
    if(!done && ~dp[pos][v1][v2][nct][status][cot] && !lead) return dp[pos][v1][v2][nct][status][cot];
    long long res = 0,end = (done ? digit[pos] : 9);
    for(long long i = 0;i <= end;i++) {
        long long tmp = nct;
        if(lead && !i) tmp = 0;
        else if(i == status) tmp++;
        else tmp = 1;
        res += dfs(pos - 1,max(cot,tmp),v1 || (i == 4),v2 || (i == 8),done && (i == end),tmp,i,lead && !i);
    }
    if(!done && !lead) dp[pos][v1][v2][nct][status][cot] = 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,0,1,0,0,1);
}
    
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 @   孤枕  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示
相见争如不见,多情何似无情。