• 数位dp 笔记


    数位dp 笔记

    数位dp一直是我的弱项,惦记好久了,最近补了补,感觉还行。

    解决的问题 & 主体思想

    解决一个区间中,满足某些条件(与每一位有关)的数的数量(或者带权的和)。

    做法:考虑求前缀 ([1,x]) 的答案。

    如果你是新手,请先考虑一下大概要怎么做,再继续看

    先把位(不一定是十进制)拆开来,然后是一个形如 "dp到第 (i) 位,..." 的 dp,一般可以用记忆化搜索,一位一位的填,使得它看起来友好一些(个人感觉这样可读性好)。

    然后要解决 (le x) 的限制。每次按照这样的规则来填数字:

    • 默认每一位都不能超过 (x) 对应的位
    • 如果有一位小于了 (x) 对应的位,则后面就没限制了

    这个很好理解。比如说现在钦点下来是 (123***)(x=123456),那后面显然不能超过 (456)

    而如果现在钦点下来是 (122***),那它就算是 (122999),也不会超过 (x)

    用一个 lim 标记维护当前是否卡到上界。注意它应该被记在 dp 状态里。

    入门 —— windy数

    求区间满足:任意相邻两位的差都不超过 (2) 的数,的数量。

    dp 状态:到第几位,当前选了什么(以决定下一个可不可以选),lim

    然后每次 dfs 扩展的时候,判断一下下一个填的是否合法,再加个记忆化,就行了。

    代码

    绕一个弯 —— 萌数

    求区间满足:将数看成字符串,没有任何长度 (ge 2) 的回文串的数,的数量。

    没有任何长度 (ge 2) 回文串 ( ightarrow) 任意一个字符和它前面一个,两个都不同。

    这样就保证了没有长度等于 (2,3) 的回文串,然后其余的回文串都是由这两种扩展出来的,自然也没有了。

    剩下就很好 dp 了,和上一个差不多。

    代码

    the end? —— 恨7不成妻

    hdu的题,我第一次学数位dp的时候被老师称作“毕业题”

    你要能把这个题写出来,你数位dp就差不多了

    当时看着老师标程打的,现在简单复习了一下,发现还挺好想的 然后把它秒了,其实就是一个傻逼缝合怪题

    要满足三个条件:

    • 不能有数位7
    • 数位和不能是7的倍数
    • 数本身不能是7的倍数

    区间求满足条件平方和。

    这里涉及到一个带权求和。带权求和状态要变一下,表示从这位开始截取,的带权和。

    比如说 (x=123),填好了 (11*),满足条件的数有 (111)(113)(114)(116)(118)

    带权和为 (1^2+3^2+4^2+6^2+8^2=126)

    为什么要做一步截取呢?因为要方便转移。考虑转移,相当于,我先确定好后面若干位,在它们的前面都填上相同的数字(这里相当于放上了 (1)

    然后填相同的数字可以看做是加法 (这里相当于 (+10)

    然后平方和,整体加,好做吧:再维护数量和一次方和,设为 dp[...][0/1/2],对应数量,和,平方和

    设现在整体加的为 (a),后面一位的 dp[...][0/1/2] 记下来为 nex[0/1/2],现在的是 cur[0/1/2],则有:

    cur[0]+=nex[0];
    cur[1]+=nex[1]+nex[0]*a;
    cur[2]+=nex[2]+2*nex[1]*a+nex[0]*a*a
    

    (就是拆括号搞一下就行)

    对于条件:

    • 每次不填 (7)
    • 记录数位和对 (7) 的余数,放在状态里,取 (0) 那个状态
    • 记录整个数对 (7) 的余数,放在状态里,取 (0) 那个状态

    代码

    小心细节 [SDOI2016]储能表

    (sumlimits_{i=0}^{n-1} sumlimits_{j=0}^{m-1} max(ioplus j-k,0))

    (n,m,kle 10^{18})

    后面等价成 (>k) 的和,减去 (>k) 的数量乘以 (k)

    拆成二进制,做数位 (dp)。记下三个 lim,表示是否卡在 (n) 的上界,(m) 的上界,(k) 的下界 (因为 (k) 那边是个 (>) 的限制)

    然后上一题类似的求一下带权和就行了,要维护一下数量和总和。

    代码

    复杂度起飞 [AHOI2009]同类分布

    由于数位 dp 的基本模型只有一个 log,所以可以带很多别的

    题意:求区间能整除数位和的数的数量

    比如 (12) 就满足条件因为 (1+2)(12) 的倍数

    (xle 10^{18})

    注意到数位和不会超过 (9 imes 18=162)

    先枚举数位和 (k),然后 dp 里设两维,一维表示当前数位和,一维表示当前数模 (k) 的余数。最后取答案就是 (\%k=0),数位和 (=k) 的那个状态

    复杂度是 ((9 imes log n^3)log n),非常暴力

    代码

  • 相关阅读:
    FAQs: 当在Outlook Explorer中右击邮件时,如何向上下文菜单添加按钮?(VSTO技术)
    C#设置系统日期和时间
    控制带有滚动条的控件(ListView,TreeView等)的滚动条显示
    HTML Clipboard Format [MSDN资料]
    Control.ProcessDialogKey 方法 ——用以处理对话框按键(TAB ESC 箭头键 等)
    span 标记的可编辑与不可编辑
    教训:System.TypeInitializationException 类型初始值设定项引发异常
    firefox 插件制作
    base64编码
    找工作了,应聘简历
  • 原文地址:https://www.cnblogs.com/LightningUZ/p/14226684.html
Copyright © 2020-2023  润新知