首页 > 其他分享 >数位DP

数位DP

时间:2024-10-25 17:32:02浏览次数:7  
标签:int len 压位 前导 DP 数位

  • 不得不说,数位DP是我掌握的最不好的一个板块。其实数位DP还挺好理解的,状态设计也一目了然,但是请小心前导零。
  • 从数位DP最基础的模版题:windy数开始做起

P2657 [SCOI2009] windy 数

  • 题意:不含前导零且相邻两个数字之差至少为 2 的正整数被称为 windy 数。windy 想知道,在 a 和 b 之间,包括 a 和 b ,总共有多少个 windy 数?\(1≤a≤b≤2×10^9\)

状态分析

  • 首先,这巨大的数据范围让我们不可能正常DP。事实上,数位DP的最明显特征就是数据范围,这就是让你明摆着写数位DP
  • 那么知道是数位DP了,考虑状态。数位DP的状态是雷同的。主要由位数、推出下一位必须的条件以及是否压位、是否有前导零等东西构成。(压位的概念后面讲)
    但状态并不是一成不变的。虽然大部分数位DP题已经相当类似,但也要“带着脑子做题”
  • 对于这道题而言,位数为9,因为我们只需要枚举每一位的数字大小就行了,我们并不关心整个数字是多少。
  • 推出下一位必须的条件很显然只有上一位数的大小,只要相减绝对值小于2,因此记下来
  • 是否压位以及是否有前导零在此题显然需要考虑。因为前导零根据题意并不算做真正的“数字”,并不需要满足“相邻数字差至少为2”的条件,因此会影响答案。
  • “压位”的意思是指是否这一位前枚举的数与我们的“上界”(就是输入进来的数)完全相同。
    比如我们已经枚举了113***(后面的*是还没枚举的),输入进来的数是113333,那我们第四位就不能是4及以上的数。
    因此我们需要记录是否有这种特殊的情况。但我们最好不要把它写进DP状态里,因为有的题会有多组数据。
    如果我们希望这种特殊的情况不影响下一组数据,我们必须每次都清空DP数组,而这会极大地增大常数,对于一些卡常题极不友好,因此养成好习惯,从模板题做起,不要把“压位”写进状态里。
  • 综上,我们设定的DP状态是 \(f_{i,j}\) 表示枚举到倒数第 \(i\) 位(倒着枚举好统计答案),上一位是 \(j\) 的情况总数
  • 至于压位与前导零,在哪里,之后讲。

粗略写法

  • 众所周知,DP有两种写法:记忆化搜索以及正着写循环。
    一般而言,数位DP使用记忆化搜索。记搜有两个优点:
  1. 可以合理方便地记下上文所说的压位以及前导零等不计入状态的信息
  2. 代码直观合理,短小精悍。写循环的话有的时候循环特别多(可以去找一些数位DP题的循环写法,十分壮观)
  • 最后是几个实现的小细节:
  1. 根据题干,枚举的数与上一位之间的差的绝对值至少为2,但如果上一位是前导零的话那么就没有这个限制
  2. 最后的边界条件需要注意。由于我使用vector来存储上界(原数),因此边界是len==-1
  3. 注意要没有压位并且没有前导零才能记忆化,因为状态中没有这两个影响最终答案的值
  4. 注意判断压位后确定上界
  5. 我们将原先的 \(a \to b\) 的区间拆分成 \(1 \to a-1\) 与 \(1 \to b\) 两个区间求值后做差
  • 有了状态与记忆化搜索的写法,我们就可以大概码出代码了。

code

(略有压行)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e9+7;
int f[20][20];
vector <int> shu;
void init(){memset(f,-1,sizeof(f));}
int dfs(int len,int last,bool qian,bool ya)
{   
	if(len==-1) return 1ll;//边界条件 
	if(!ya&&!qian&&f[len][last]!=-1) return f[len][last];//注意不压位无前导零才能记忆化 
	int up=ya?shu[len]:9,res=0;//注意压位的上界 
	for(int i=0;i<=up;i++){
		if(abs(last-i)>=2||qian)//如果是有前导零就可以无视条件 
		res+=dfs(len-1,i,qian&&(!i),ya&&(i==up));
		//状态简洁一点,不要像某些 题解一样写的一大堆,其实一行就行了 
	}
	if(!ya&&!qian) f[len][last]=res;return res;
}
int work(int x)
{
	shu.clear();//记得清空 
	while(x){shu.push_back(x%10),x/=10;}//用vector存上界 
	return dfs(shu.size()-1,-2,1,1);//从高向低位枚举 
}
signed main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);//关流,好习惯,但只能用cin 
	int l,r;cin>>l>>r;init();
	cout<<work(r)-work(l-1)<<'\n';//做差 
	return 0;
}

时、空复杂度

  • 时间复杂度一般而言就是你开的数组大小。因为一般而言你会将整个数组都跑一遍,又因为记忆化,所以就是数据大小
  • 为什么要强调空间复杂度呢?因为有一些毒瘤卡常题,因此注意状态设计,需要离散化的离散化,需要再压缩的再压缩

标签:int,len,压位,前导,DP,数位
From: https://www.cnblogs.com/allforgod/p/18502998

相关文章

  • wordpress接入腾讯云COS,50G月免费流量
    对象存储COS是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持HTTP/HTTPS协议访问的分布式存储服务。腾讯云COS的存储桶空间无容量上限,无需分区管理,适用于CDN数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景,适用于网站需要实时访问、频繁访......
  • 【2024有效】WordPress忘记密码找回登录密码的最简单有效的方法
    这个找回Wordpress后台密码密的方法,前提是,可以操作数据。 最近忘记了极客侠网站登陆密码,还是按照以前的方法,进入数据库直接修改数据库,但是现在wordpress密码的加密不是简单的MD5所以不能用一个md5加密好的密码去替换数据库,这里的关键所在就是不知道现在的加密方式,于是又百......
  • 网络协议基础(2):socket套接字及TCP、UDP的实现
    socket套接字及TCP、UDP的实现socket套接字socket的基本概念socket的类型Socket的工作流程Socket的编程接口(C++示例)1.创建Socket2.绑定地址3.监听连接4.接受连接5.连接到服务器6.发送数据7.接收数据8.关闭Socketsocket相关的结构体sockaddr结构体sockaddr......
  • C# UDP组播客户端【UDPClient】
    方式一UdpClientudp=newUdpClient(5566);//要通过其进行通信的本地端口号。5566是源端口udp.JoinMulticastGroup(IPAddress.Parse("224.0.0.4"));//将UdpClient添加到多播组;IPAddress.Parse将IP地址字符串转换为IPAddress实例IPEndPointmu......
  • C# UDP广播启动服务和客户端【Socket】
    服务端:Socketsocket=newSocket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);//初始化一个Scoket协议IPEndPointiep=newIPEndPoint(IPAddress.Any,9095);//初始化一个侦听局域网内部所有IP和指定端口EndPointe......
  • 基于DPAPI+RDP技术实现本地打开远程程序,并映射到本地机器桌面上
    本教程使用工具所使用的环境说明:启动器开发工具:VS2022启动器所用客户端技术:.NET8+WPF启动器其他技术:DPAPI启动器发布的可执行程序,系统要求:Windows7以及以上,X64如果需要本程序,可以在网盘获取。网盘地址:通过网盘分享的文件:RemoteShadowApp.7z链接:https://pan.baidu.com......
  • 【ModbusTCP与Profibus DP双向互转说明】
        Profibusdp和ModbusTCP均为工业通信协议。ModbusTCP为串行通讯协议,已成为工业领域通讯协议的业界标准。Modbus是现在国内工业领域应用最多的协议,不只PLC设备,各种终端设备,比如水控机、水表、电表、工业秤、各种采集设备。而Profibus为自动化技术的现场总线标准,广泛......
  • 每日OJ题_牛客_DP10最大子矩阵_二维前缀和_C++_Java
    目录牛客_DP10最大子矩阵_二维前缀和题目解析C++代码Java代码牛客_DP10最大子矩阵_二维前缀和最大子矩阵_牛客题霸_牛客网(nowcoder.com)描述:        已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1*1)子矩......
  • 动态规划之简单多状态 dp 问题(下)
    文章目录买卖股票的最佳时机买卖股票的最佳时机含手续费买卖股票的最佳时机III买卖股票的最佳时机IV买卖股票的最佳时机题目:买卖股票的最佳时机思路状态表示:dp[i]表示第i天结束后,处于某个状态的最大利润,我们可以细分为,处于“买入”、“可交易”、“”三种状......
  • 树形限制的排列生成dp
    对于这类树形限制的生成排列的题记录两种不同的做法\(\color{blue}\textbf{[例题]}\)第一种方法(暴暴暴暴暴力dp)P4099[HEOI2013]SAOP3757[CQOI2017]老C的键盘第二种方法(容斥+dp)P5405[CTS2019]氪金手游题面生成一个大小为n的排列,满足n-1条形如p[x]>p[y]......