【算法笔记】数位dp小结

资料链接:

入门ppt
link1:记忆化方式
link2
link3
论文1
论文2
//=====================//
记忆化的数位dp:
通常而言,有四个参数必须 dp( pos, flag, limit )
pos表示当前正在枚举的数位。
flag标志已经枚举的前缀是否某种性质(前面的数位和,是否含有某个数,前一个枚举的数等等。。),当然flag可以有多个。
limit表示当前是否为上限,有时还会记录是否有前导0。
相较而言,记忆化搜索更容易编写,需要维护的细节更少。

假设要对数位中没有5的数计数。

int digit[Maxn], dp[Maxn][flag];

// 在程序最开始初始化一次即可(假设有多个区间需要询问),想想为什么
void init() {
    memset(dp, -1, sizeof(dp));
}

// flag 是否没有5
int go (int pos, int limit, int flag) {
    if (pos < 0) {
        return flag == 1;
    }

    if (limit || dp[pos][flag] == -1) {
        int tmp = 0;
        int last = limit ? digit[pos] : 9;
        for (int i=0;i<=last;++i)
            tmp += go (pos - 1, limit && (i == last), flag && (i != 5));
        if (limit) return tmp; // 上界要单独计算,不能存状态
        dp[pos][flag] = tmp;
    }
    return dp[pos][flag];
}

// count [1, x]
int Count(int x) {
    int len = 0;
    while (x) {
        digit[len ++] = x % 10; x /= 10;
    }
    return go (0, 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值