算法-数位dp

本文介绍了数位动态规划(数位dp)的概念,通过讲解ZJOI2010年数字计数问题和SCOI2009年windy数问题,阐述了循环递推和记忆化搜索两种方法。数位dp常用于计算在特定数位限制下的数的数量,文章提供了详细的解决方案和代码示例。
摘要由CSDN通过智能技术生成

算法-数位dp

前置知识: dp \texttt{dp} dp Dfs \texttt{Dfs} Dfs

参考文献

https://www.cnblogs.com/y2823774827y/p/10301145.html
https://www.luogu.com.cn/blog/mak2333/solution-p2602


Introduction \texttt{Introduction} Introduction

数位 dp \texttt{dp} dp 是指求在数位限制下有多少满足要求的数的 dp \texttt{dp} dp。例如,求“在 [ L , R ] [L,R] [L,R] 范围内连续出现过 3 3 3 3 3 3 的数”,“相邻两位之间差为质数的 5 5 5 位数”或“在 [ L , R ] [L,R] [L,R] 区间内 6 6 6 出现的次数”。读完这篇文章以后,你就都会做了。

数位 dp \texttt{dp} dp 有两种主要方法: 循环递推 \color{6699e9}\texttt{循环递推} 循环递推 记忆化搜索 \color{77c650}\texttt{记忆化搜索} 记忆化搜索

先讲 循环递推 \color{6699e9}\texttt{循环递推} 循环递推,例题是数字计数。


Description \color{6699e9}\texttt{Description} Description

[ZJOI2010]数字计数
求在 [ a , b ] [a,b] [a,b] 区间内的数 0 ∼ 9 0\sim9 09 数字分别出现次数,前导 0 0 0 不算。
数据范围: 1 ≤ a ≤ b ≤ 12 1\le a\le b\le 12 1ab12


Solution \color{6699e9}\texttt{Solution} Solution

为了讲得更透彻,蒟蒻会把同一个东西用不同的方法多次描述,文章较长,请见谅。

Step 1 预处理

s u m i , j ( 1 ≤ i ≤ 12 , 1 ≤ j ≤ 9 ) sum_{i,j}(1\le i\le 12,1\le j\le 9) sumi,j(1i12,1j9) 表示数字 j j j 在满 i i i 位整数( [ 1 , 1 0 i − 1 ] [1,10^i-1] [1,10i1])中出现的次数。因为除了 0 0 0 以外, 1 ∼ 9 1\sim 9 19 在这题中其实是一模一样的,所以 s u m i , 1 = s u m i , 2 = . . . = s u m i , 9 sum_{i,1}=sum_{i,2}=...=sum_{i,9} sumi,1=sumi,2=...=sumi,9

所以蒟蒻们还不如直接用 s u m i sum_i sumi 表示 s u m i , j sum_{i,j} sumi,j,表示数字 1 ∼ 9 1\sim9 19 在满 i i i 位整数中出现的次数。所以 s u m 1 = 1 sum_1=1 sum1=1,因为 s u m 2 sum_2 sum2 可以由 s u m 1 sum_1 sum1 个数前面加 0 ∼ 9 0\sim 9 09 递推得,也可以把数放在首位,所以 s u m n = 10 s u m n − 1 + 1 0 n − 1 ( 2 ≤ n ) sum_n=10sum_{n-1}+10^{n-1}(2\le n) sumn=10sumn1+10n1(2n) s u m sum sum 数列打表出来就是 1 , 20 , 300 , 4000 , . . . 1,20,300,4000,... 1,20,300,4000,...

code

void pro(){
    //其实代码很短
	ten[0]=1;//10^0=1
	for(int i=1;i<=12;i++){
   
		ten[i]=ten[i-1]*10;
		sum[i]=sum[i-1]*10+ten[i-1];
	}
}

Step 2 DP
预处理完 s u m i sum_i sumi 后,可以抓一只 p p p 位数 n n n 0 ∼ 9 0\sim9 09 [ 1 , n ] [1,n] [1,n] 中出现的次数。首先设 n l i ( 1 ≤ i ≤ p ) nl_i(1\le i\le p) nli(1ip) 表示 n n n 的从右往左第 i i i 位的数字。即 n l i = ⌊ n m o d    1 0 i 1 0 i − 1 ⌋ nl_i=\lfloor\frac{n \mod 10^i}{10^{i-1}}\rfloor nli=10i1nmod10i

code

int p; lng bit=n;
for(p=0;n;n/=10) nl[++p]=n%10;//最后p就是n的位数

然后令 f j

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值