首页 > 其他分享 >数位dp笔记

数位dp笔记

时间:2024-02-04 10:57:18浏览次数:22  
标签:数字 int mask isnum 笔记 limit str dp 数位

数位dp学习笔记

数位dp的问题题型一般是给定一个闭区间[L,R],求这个区间中满足“某种条件”的数的个数的总数
对于这类问题,我们首先统计[L,R]范围的满足条件的数字转化成统计[1,N]内满足条件的数字的数量

那么 ans[L,R]=ans[1,R]-ans[1,L-1];

先将n转换成字符串str,使用记忆化搜索

定义dfs函数

function<int(int,int,bool,bool)> dfs = [&](int i,int mask,int limit,int isnum)->int{  
};
  • i表示构造第i位及其之后数位的合法方案数
  • mask表示之前的选择的数字的集合,使用二进制表示集合,有些题比如每个数字只能选择一个,那么就需要mask的限制
  • limit表示当前是否受到了右区间n的约束,如果limit = true,表示当前位选择的数字不能超过 str[i]中的数字,因为构造的数字不能超过n,如果limit = false,则可以填0到9
  • isnum表示i前面是否填了数字,这是为了避免前导0导致mask的误判,比如010是合法的,但是会因为有前导0而判重,导致误认为其不合法,如果isnum = false,则表示i之前都是跳过的,表示并没有填数字,若为假,则当前位可以跳过(不填数字),或者要填入的数字至少为 1;若为真,则要填入的数字可以从 0 开始。例如 n=123,在 i=0 时跳过的话,相当于后面要构造的是一个 99 以内的数字了,如果 i=1 不跳过,那么相当于构造一个 10 到 99 的两位数,如果 i=1 跳过,相当于构造的是一个 9 以内的数字。

递归入口

dfs(0,0,true,false);
  • 表示从str[0]开始枚举,一开始没有选择任何数字,所以集合为空,一开始是最高位所以一定会受到n的限制,所以为true,一开始没有填数字,所以isnum为false

对于mask使用二进制表示集合的方式,我们将mask的每一二进制位从低到高进行表示,i=1表示在集合中,i=0表示不在,比如集合\(\{0,2,3\} = 1101\)

对其操作的话,有两种操作:

  • 判断元素d是否在集合中:x>>d&1 可以取出x的第d个比特位,如果为1则证明在集合中
  • 把元素d加到集合中,x|(1<<d)

步骤:例题[2376. 统计特殊整数 ](2376. 统计特殊整数 - 力扣(LeetCode))

class Solution {
public:
    int countSpecialNumbers(int n) {
        auto str=to_string(n);
        int m = str.length(); 
        int mem[m][1<<10]; //左移10位,可以表示0~9的集合
        memset(mem,-1,sizeof(mem));//全部赋值-1,可以判断是否记忆过
        function<int(int,int,bool,bool)> dfs=[&](int i,int mask,bool limit,bool isnum)->int{
            if(i==m) return isnum; //到达了最后一位,通过判断是否非空进行累加
            if(!limit&&isnum&&mem[i][mask]!=-1){ //有记忆返回记忆
                return mem[i][mask];
            }
            int res=0;//统计总数
            if(!isnum) res=dfs(i+1,mask,false,false); //如果i之前跳过了,则可以继续跳过,集合无变化,之后也将不会受限
            int up=limit? str[i]-'0':9; //up表示可以去取的数字d的上限,若没有限制,则0~9都可以取
            for(int d=1-isnum;d<=up;d++){ //如果i之前跳过了,那么只能从1开始,否则可以从0开始,直到上限
                if((mask>>d&1)==0){ //判断d是否在集合中,不在的话可以选择
                    res+=dfs(i+1,mask|(1<<d),limit&&d==up,true);//如果之前未受到限制,则一定比n小,之后也不会受到限制,或者说之前受到了限制,但是这一位并没有到达上限,则也一定会严格小于n,下一位不会受到限制
                }
            }
            if(!limit&&isnum){ //如果没受到限制同时非空,就可以记忆下来
                mem[i][mask]=res;
            }
            return res;
        };
        return dfs(0,0,true,false);
    }
};

步骤:[P4999 烦人的数学作业 - 洛谷](P4999 烦人的数学作业 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))

int work(int x){
    auto str=to_string(x);
    int m=str.size();
    int mem[200][200];
    ms(mem,-1);
    function<int(int,int,bool,bool)> dfs=[&](int i,int sum,bool limit,bool isnum)->int{
        if(i==m) return isnum?sum:0;
        if(!limit&&isnum&&mem[i][sum]!=-1) return mem[i][sum];
        int ans=0;
        if(!isnum) ans=(dfs(i+1,sum,false,false));
        int up=limit?str[i]-'0':9;
        for(int d=1-isnum;d<=up;d++){
            ans=(ans+dfs(i+1,sum+d,limit&&up==d,true))%MOD;
        }
        if(!limit&&isnum){
            mem[i][sum]=ans;
        }
        return ans;
    };
    return dfs(0,0,true,false);
}
inline void solve(){
    int l,r;
    cin>>l>>r;
    l--;
    cout<<(work(r)-work(l)+MOD)%MOD<<"\n";
}

借鉴资料:

标签:数字,int,mask,isnum,笔记,limit,str,dp,数位
From: https://www.cnblogs.com/KrowFeather/p/18005765

相关文章

  • Pandas库学习笔记(4)---Pandas Panel
    PandasPanel  PandasPanel基本操作Panel数据3D容器.术语 Paneldata 源自计量经济学,名称来之于pandas− pan(el)-da(ta)-s.3个轴的名称描述如下-−items −轴0,每个items都对应一个包含在其中的DataFrame。major_axis −轴1,它是每个DataFrame的索引(行)。minor......
  • 《周期》霍华德马克思 读书笔记
    第七章投资人的心理和情绪钟摆周期像钟摆从最左端摆向平衡位置时他不会停下而会继续向右摆动,直到力量不再支持他向右继续摆动,调头返回投资人的心理在绝对乐观到绝对悲观之间摆动,绝对悲观时看到资产认为他像一个会带来成本的大楼,没有想到他能租出去带来收益。绝对乐观时认为资......
  • 图论算法学习笔记
    ybt1376floyd#include<iostream>#include<climits>#include<cstring>#include<queue>#include<vector>#defineinfinity0x3f3f3f3f#defineN105intn,m,G[N][N],dist[N][N];intmain(){ memset(dist,infinity,sizeof(dist)); st......
  • Docker笔记(一)docker 在linux里面的安装
    Docker笔记(一)docker在linux里面的安装为什么使用docker(docker理念)在开发环境,将源码+配置+软件等其他项目运行的所有的东西,都打包,直接都给运维,这样运维就不需要自己搭建项目运行的环境了,因为你已经拿到了开发人员本地的全部的东西,相当于拿到开发人员全部的东西,直接在运维那里就......
  • 【学习笔记】字符串
    1.KMP【模板】KMP朴素的比对是如下的:for(inti=0;i<a.size()-b.size();i++){ for(intj=0;j<b.size();j++){ if(a[i+j]!=b[j])break; if(j==b.size()-1)cout<<i<<''; }}设A串长度\(n\),B串长度\(m\),显然这么做是\(O(nm)\)的。很容易想到一个错误优化:如果失......
  • 花店橱窗(线性DP)
    线性DP——花店橱窗谨以此题解献给线性dp最后一道题题目大致Descriptionxq和他的老婆xz最近开了一家花店,他们准备把店里最好看的花都摆在橱窗里。但是他们有很多花瓶,每个花瓶都具有各自的特点,因此,当各个花瓶中放入不同的花束时,会产生不同的美学效果。为了使橱窗里的花摆放的最......
  • 【笔记】快速傅里叶变换
    快速傅里叶变换0记号\(\exp(x)=e^x\)。1复数(Complex)1.1三种形式代数形式:\(z=a+bi\),其中\(a,b\in\mathbbR\)。三角形式:\(z=r(\cos\theta+i\sin\theta)\),其中\(r=\sqrt{a^2+b^2}\)(\(a,b\)是在代数形式中定义的)。指数形式:\(z=r\cdote^{i\theta}\)。根据......
  • 数学の总结(笔记 + 自学)
    写在「开始」之前:由于笔者从初中二年级就踏上了数学的学习路程,再加上笔者理解力比较强,若有说的不明白的地方,还望指正,thx1.集合我们知道,一个字母可以表示一个数,比如说\(a=0\)。那么,有没有一种东西,可以容纳很多个字母呢?答案是肯定的,数学家们提出了一种叫做集合的一种容器,其中......
  • 动态规划--线性dp
    线性dp动态规划步骤:1.状态表示用几维度的数组,每一维度的意思。2.状态计算状态转移方程   题目:数字三角形给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最......
  • einops 学习笔记:基础篇
    参考:https://einops.rocks/1-einops-basics/einops(EinsteinOperations)提供了一种语法来便捷地操纵张量。einops支持大多数张量库(当然包括numpy和pytorch)。einops针对所有张量库的语法都完全一致。einops不会影响反向传播的正常进行。这些特性意味着einops可以和现有......