首页 > 其他分享 >数位dp总结---LZM

数位dp总结---LZM

时间:2023-09-07 20:45:51浏览次数:34  
标签:lead int top len --- 枚举 LZM dp 数位

数位DP总结 BY----LZM

当你学会了数位DP,那么你会发现,在考场上,你也写不出来。

首先给出一道例题:

给出一个区间 \([l,r]\) ,求出区间内每个数字的数位和,答案 \(\bmod \ 998244353\),\(1\le l,r \le 10^{18}\)。

样例输入           样例输出
24 69                411

考虑枚举从 \(l\) 到 \(r\) ,对于每个数都拆分成数位,然后暴力的加。
复杂度很显然是 \(O(rlogr)\)爆chao,非常痛苦。

考虑优化,先想从 \(1\) 到 \(l-1\) ,再想从 \(1\) 到 \(r\) ,然后发现答案是一个前缀和的形式,两者相减即可得到答案。

所以我们只要有一个东西能够解决从 \(1\) 到 \(x\) 的答案就可以轻松的求出来,这里给出方法。

假设从高位枚举到低位,对于每一个数位都可能有10个数字(0,1,2....8,9),为什么说可能呢,因为可能这个数字太大了,会超过 \(x\) ,的上界,比如在枚举 \(x=123\)时,我们已经枚举到了第二位,

我们枚举的---》 \(1 \Box \Box\)

枚举的第一个数不能超过1,同样的,第二位不能超过二。

还有一种情况,我们枚举的---》 \(0 \Box \Box\)

发现有前导零的情况,那么对于这一种我们就要记录下来。

那么怎么实现呢???

记忆化!搜!索!

我们在 \(dfs\) 中记录几个参数:

  • \(len\):代表目前从高位到低位枚举的位数
  • \(lead\):代表是否有前导零
  • \(top\):代表是否到了上界
  • \(sum\):代表此时的数位和

然后在开一个 \(4\) 维的 \(dp\) 记忆化数组。

为什么记忆化可以?!

因为 \(dp\) 数组记录的状态是唯一的,如果当前状态已经被搜过了,那么后面搜的一定是一样的。

以下给出代码。

#include<bits/stdc++.h>
#define int long long 

const int p=1e9+7;

int a[20];
int f[20][3][3][200];

int dfs(int len,int lead,int top,int sum)
{
    if(!len)return sum;//没有位数了
    if(!lead && !top && f[len][lead][top][sum]!=-1)return f[len][lead][top][sum];//状态被搜过了,直接回去
    int bound=top?a[len]:9,res=0;//如果上界到了就枚举到这一位最多能枚举到的
    for(int i=0;i<=bound;i++)res=(res+dfs(len-1,lead && !i,top && i==bound,sum+i))%p; 
    if(!lead && !top)f[len][lead][top][sum]=res;
    return res;
}

int read()//快读就是好
{
    int x=0,s=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')s=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-48;
    return x*s;
}

signed main()
{
    memset(f,-1,sizeof(f));//记得清空
    int n=read()-1,ans=0,cnt=0;//初始n记得减1
    while(n)a[++cnt]=n%10,n/=10;//从高位到低位
    ans-=dfs(cnt,1,1,0);
    cnt=0;
    n=read();
    memset(f,-1,sizeof(f));
    while(n)a[++cnt]=n%10,n/=10;
    ans+=dfs(cnt,1,1,0);
    printf("%lld\n",(ans%p+p)%p);
    return 0;
}

接着下一道题

不含前导零且相邻两个数字之差至少为 \(2\) 的正整数被称为 \(windy\) 数。在 \(a\) 和 \(b\) 之间,包括 \(a\) 和 \(b\) ,总共有多少个 \(windy\) 数?

这个和上面的差不多,只是要换一下参数

记录前一个数,以及前导零和上界就可以和上一个题一样了,但是要记得一开始传参要从-2开始,因为一开始可以随便填。

#include<bits/stdc++.h>
#define int long long 

using namespace std;

const int N=30;

int n;
int a[N];
int ans;
int f[N][N][N][N];

void init(int x)
{
    memset(a,0,sizeof(a));
    n=0;
    while(x)a[++n]=x%10,x/=10;
}

int dfs(int len,int pos,int lead,int top)
{
    if(!len)return 1;
    if(!top && !lead && f[len][pos][lead][top]!=-1)return f[len][pos][lead][top];
    int bound=top?a[len]:9,res=0;
    for(int i=0;i<=bound;i++)
    {
        if(abs(pos-i)<2)continue;
        if(lead && !i)res+=dfs(len-1,-2,1,top && i==bound);
        else res+=dfs(len-1,i,0,top && i==bound);
    }
    if(!lead && !top)f[len][pos][lead][top]=res;
    return res;
}

int read()
{
    int x=0,s=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')s=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-48;
    return x*s;
}

signed main()
{
    memset(f,-1,sizeof(f));
    int x=read();
    x--;
    init(x);
    ans-=dfs(n,-2,1,1);
    x=read();
    init(x);
    memset(f,-1,sizeof(f));
    ans+=dfs(n,-2,1,1);
    cout<<ans;
    return 0;
}

那么其他的就差不多了。

总结:记忆化搜索!

然后你就可以AK \(LSYOI\) 上面的数位DP了

标签:lead,int,top,len,---,枚举,LZM,dp,数位
From: https://www.cnblogs.com/LZMkingNB/p/17686007.html

相关文章

  • qt程序调用cuda-11.7,cmake编译时,提示:"CMakeCUDACompilerId.cu" failed. Compiler:
    报错显示:Running/home/wc/software/cmake-3.26.3-linux-x86_64/bin/cmake/home/wc/work/junke_src/missile-sim'-GCodeBlocks-UnixMakefiles'in/home/wc/work/junke_src/build/debug.CMakeErrorat/home/wc/software/cmake-3.26.3-linux-x86_64/share/cmak......
  • vue-router 路由模式有几种?
    VueRouter提供了三种路由模式:######1:Hash模式(默认):在URL中使用带有#符号的哈希值来管理路由。例如:http://xxxx.com/#/path。在Hash模式下,当URL的哈希值发生变化时,浏览器不会向服务器发送请求,而是通过监听hashchange事件来进行路由导航。######2:History模式:使用HTM......
  • 【API Management】使用 APIM Inbound Policy 来修改Content-Type Header的值
    问题描述在使用APIM提供API服务管理的场景中,遇见了客户端请求时候发送的请求Header中的Content-Type不满足后台服务器的要求,但是在客户端要求客户修改代码难度较高。所以面对这样的情况,是否在APIM端修改为对请求的Content-Type进行覆写呢?问题解答可以的。APIM支持通过设置策略(Poli......
  • 论文解读(CST)《Cycle Self-Training for Domain Adaptation》
    Note:[wechat:Y466551|可加勿骚扰,付费咨询]论文信息论文标题:CycleSelf-TrainingforDomainAdaptation论文作者:HongLiu,JianminWang,MingshengLong论文来源:2021 论文地址:download 论文代码:download视屏讲解:click......
  • 苍穹外卖-Day01
    苍穹外卖-Day011.项目整体介绍1.1项目定位项目的定位:专门为餐饮企业(餐厅,饭店)定制的一款软件产品。项目主要分为两个端:(1)管理端:外卖商家使用。(2)服务端:点餐用户使用。1.2项目的功能架构项目的功能架构:体现项目的业务功能模块1.......
  • transition动画和transition-group动画组
    1.transition和transition-group介绍transition会在一个元素或组件进入和离开DOM时应用动画transition-group会在一个v-for列表中的元素或组件被插入,移动,或移除时应用动画区别2.transition2.1基本用法2.2name属性3.transition-group4.参考https://blog......
  • php-PhpSpreadsheet设置生成的excel文件列宽度及字体大小
    usePhpOffice\PhpSpreadsheet\Spreadsheet;usePhpOffice\PhpSpreadsheet\Writer\Xlsx;//创建新的Excel实例$spreadsheet=newSpreadsheet();//获取当前工作表$worksheet=$spreadsheet->getActiveSheet();//设置列宽自动调整的范围$worksheet->getStyle('B1:C1'......
  • CSP-J2022 游记
    2022年,总算是拿到了的CSP-J1=。好吧,压线(算是)。100+60+0+15=175HN分数线170。真的很悬。。。情况T1sowater。10分钟就切了,本来看见题目还以为要快速幂(忘了),吓死了。T2看见\(m\)的范围,感觉十分的巧妙,推了30分钟公式,推出了。。。啥也没推出来。。。15分钟暴力,60分到手......
  • jiangyuchen12码风 截至 2022-12-27 11:09
    最后一条码风改之前的记录那么多人的博客都有TA的码风,我也写一下吧头文件一般使用万能头文件,因为绝对看不到[Error]'***'doesnotnameatype之类的错误常量有,一般是K,N,看题目变量名字变量输入&输出一般用cin,cout大括号写题是这样while(1){……}具体......
  • 数据结构代码题-栈、队列
    目录栈、队列栈队列栈和队列的应用栈、队列栈栈的定义#defineMaxSize100//储存空间的初始分配量typedefintElemType;typedefstruct{inttop;//栈顶指针ElemTypedata[MaxSize];//存放元素的动态数组空间}sqstack;链栈的数据结构描述type......