首页 > 其他分享 >数位dp

数位dp

时间:2024-10-23 19:10:38浏览次数:8  
标签:lim ll up leq zero sum dp 数位

数位 dp

本质是记忆化搜索。

\(lim\) 为 \(1\),表示当前位之前都是最大的数,当前位的大小受限制,不是 1~9,是 1~up。

\(zero\) 为 \(0\),表示这一位之前为前导 0。

\(lim\) 的转移:lim && (i == up)

\(zero\) 的转移:zero || i

例题1

P2602 [ZJOI2010] 数字计数

给定 \(a\) 和 \(b\),求在 \([a,b]\) 的所有整数中,\(0 \sim 9\) 各出现了几次。\(1 \leq a \leq b \leq 10^{12}\)。

思路:

从高位到低位枚举,对于每一位,当前位的答案 \(ans\) 初始为 0,然后枚举这一位数字的种类,用更新后的状态来处理答案累加。

当位数为 0 时说明处理完了,返回当前的答案。

处理的过程中开 \(dp\) 数组存储 dfs 时的状态,实现记忆化。

ll n, m, k;
ll num[20], len;
ll f[20][20][2][2];

ll dfs(ll x, ll lim, ll zero, ll sum, ll d)
{
    if(x == 0) return sum;
    ll ans = 0;
    if(f[x][sum][lim][zero] != -1) return f[x][sum][lim][zero];
    ll up = 9;
    if(lim) up = num[x];
    fr(i, 0, up)
    {
        ans += dfs(x-1, lim && (i == up), zero || i, sum + ((zero || i) && (i == d)), d);
    }

    return f[x][sum][lim][zero] = ans;
}

ll Calc(ll x, ll d)
{
    len = 0;
    while(x)
    {
        num[++len] = x % 10;
        x /= 10;
    }
    memset(f, -1, sizeof(f));
    return dfs(len, 1, 0, 0, d);
}

int main()
{
    ll l = re, r = re;
    fr(i, 0, 9)
        W(Calc(r, i) - Calc(l-1, i), ' ');
    return 0;
}   

例题2

https://codeforces.com/gym/101982/attachments

给定两个整数 \(k\) 和 \(b\),\(1 \leq k \leq 1000\),\(1 \leq b \leq 128\)。

求 \([0,2^b-1]\) 内的所有整数中,为 \(k\) 的倍数的数在二进制表示下 \(1\) 的数量的总和。答案对 \(1e9+9\) 取模。

思路:

以二进制按位考虑。发现对于任意一个二进制数,左移一位,\(1\) 的数量不会被改变。

开三个状态。\(x\) 为当前位数,\(num1\) 为当前 \(1\) 的个数,\(mod\) 为当前这个数除以 \(k\) 的余数。

对于每一位,枚举当前位是 \(0\) 还是 \(1\),转移答案和余数,转移过程比较简单。

ll n, m, k, b;
ll f[130][130][1010];
ll Mo = 1e9 + 9;

ll dfs(ll x, ll num1, ll mod)
{
    if(x <= 0)
    {
        if(mod != 0) return 0;
        return num1;
    }

    if(f[x][num1][mod] != -1) return f[x][num1][mod];
    ll ans = 0;

    fr(i, 0, 1)
    {
        ans += dfs(x-1, num1 + i, (mod * 2 + i) % k);
        ans %= Mo;
    }
    
    f[x][num1][mod] = ans;
    return ans;
}

int main()
{
    k = re, b = re;
    memset(f, -1, sizeof(f));
    W(dfs(b, 0, 0), '\n');
    return 0;
}   

标签:lim,ll,up,leq,zero,sum,dp,数位
From: https://www.cnblogs.com/EdisonBa/p/18498102

相关文章

  • 概率DP
    概率DP是DP中一个非常重要且较难的DP类型。其题型灵活多变,尤其爱与树形DP结合,同时很可能需要各种数据结构优化。其主要考点便是DP方程的建立与维护。由于“概率”二字,许多时候分类讨论与小数运算也是不可避免的。因此,概率DP对选手的逻辑思维与代码能力也有很高的要求,可以说是DP......
  • AtCoder DP Contest 速通指南
    题单链接这是AT之前办的一场DP专题,里面都是很经典的问题,可以帮助大家复习DP的套路,个人感觉对于巩固基础来说质量很高,建议大家去去联系一下,尽量不要看题解。本博客只讨论了绿色及以上难度的题目,下面是我的题解。ICoins设\(f_{i,j}\)表示扔到了第\(i\)个,有\(j\)个......
  • TCP与UDP协议
    (1)TCP协议面向连接、可靠、基于字节的传输,IP报头中协议号为6。一般用于对可靠性要求较高的应用。(2)UDP协议无连接、不可靠、基于报文的传输,IP报头中协议号为17。主机不需维持连接状态具有较高的传输效率,可靠性由应用层来提供。TCP报头结构①源端口和目的端口:传输层与......
  • 杭州 Day 4 上午 状压 dp
    状压一类杂题P1896[SCOI2005]互不侵犯先预处理出一行的所有可能状态\(S\),应当满足\(S\&(S≫1)=0\),因为不能有相邻的国王。用\(f(i,S,j)\)表示考虑了前\(i\)行,第\(i\)行的状态是\(S\),当前已经放了$$个国王的方案数。转移直接枚举第\(i−1\)行的状态\(T......
  • 提高组专题 dp4
    A[PA2021]OddeskidodeskiDP挺显然的,但我推错了……。\[\begin{split}dp_{i+1,j,1}&+=\sum(dp_{i,j,1}+dp_{i,j,0})\timesj\\dp_{i+1,j+1,0}&+=\sumdp_{i,j,1}\times(m-j)\\dp_{i+1,j,0}&+=\sumdp_{i,j,0}\times(m-j)\end{split}\]#include&......
  • 如何隐藏wordpress主题或插件的更新提示
    如何隐藏WordPress主题或插件的更新提示平常在维护WordPress时,有时候会因为一些错误或者兼容性等问题,我们不能马上升级主题或插件到最新的版本,需要保持旧版本,但是这时候会有一个问题就是每次点开后台都会看到非常显眼的小红点,影响后台体验在本文中我们就来说一下如何在不升级的......
  • Woodpecker: 多模态大语言模型的幻觉纠正先锋
    Woodpecker项目简介在人工智能和自然语言处理领域,多模态大语言模型(MLLMs)的快速发展引人注目。然而,这些模型面临着一个严峻的挑战-幻觉问题。所谓幻觉,指的是模型生成的文本内容与输入图像不一致的现象。为了解决这个问题,研究人员提出了各种方法,其中大多数依赖于特定数据......
  • P4170 [CQOI2007] 涂色 区间 dp
    P4170[CQOI2007]涂色区间dp模板题,不理解为什么是蓝。将现在考虑的区间\([l,r]\)分为\([l,k]\)和\([k+1,r]\),如果\(s_l=s_r\)就可以一起涂,少涂一次。方程:\[dp_{l,r}=\min_{k=l}^{r-1}dp_{l,k}+dp_{k+1,r}-[s_l=s_r]\]代码:#include<bits/stdc++.h>usingnamespac......
  • Linux 操作系统 dpkg-trigger 命令介绍和使用案例
    Linux操作系统dpkg-trigger命令介绍和使用案例dpkg-trigger是Debian和基于Debian的Linux发行版(如Ubuntu)中的一个命令,用于管理软件包的触发器。触发器是一种机制,允许软件包在安装、卸载或升级时执行特定操作。命令概述dpkg-trigger命令用于通知系统某个事件的发......
  • linux 操作系统下 dpkg-statoverride命令介绍和使用案例
    dpkg-statoverride是一个用于管理Debian和基于Debian的Linux发行版(如Ubuntu)中文件的所有权和权限的命令。它允许用户在软件包安装时覆盖文件的默认所有权和权限设置命令概述dpkg-statoverride命令提供了三种基本功能:添加覆盖删除覆盖列出当前的覆盖命令语法bash......