首页 > 其他分享 >【学习笔记】数位 dp

【学习笔记】数位 dp

时间:2023-08-01 21:24:40浏览次数:306  
标签:10 20 笔记 计数 maxn dp 数位

数位 dp

前置知识:

oi-wiki

概念:

数位 dp,就是一个用来计数的动态规划,将一个长数分解为一个一个数位上的数进行统计。

例如:求 \(a-b\) 区间不包含 \(c\) 的数的个数,保证 \(0\leq a\leq b\leq 2\times 10^9\)。

空间限制 256MiB,时间限制 1000ms。

这个范围一眼暴力 TLE,等死。

直接动态规划记录数字?MLE 等着你。

所以有个东西叫数位 dp,它一般应用于:

  • 求给定区间 \([a,b]\) 之内的符合条件的数的个数,即结果是计数,有左右边界。

  • 条件与数的大小无关,与各数位上的数有关。、

  • 上界较大,如(\(10^{18}\))。

实现:

从左边界 \(l\) 数到右边界 \(r\),过程中拥有非常多的重复部分,如:\(l=309\) 数到 \(r=831\),之中有非常相似的过程:从 \(400\) 数到 \(499\),从 \(500\) 数到 \(599\),诸如此类后两位从 \(00\) 变为 \(99\) 的计数,这样的过程产生的计数答案可以放入一个通用的数组,对于这样的数组我们设计转移状态,进行动态规划。

有时也会用到一些计数技巧:

\[ \begin{aligned} ans_{l,r}=ans{0,r}-ans{0,l-1} \end{aligned} \]

对于统计答案,往往采用记忆化搜索或是递推。

就伴着第一道例题讲实现吧:

[ZJOI2010] 数字计数

题目链接

[ZJOI2010] 数字计数

题目描述

给定两个正整数 \(a\) 和 \(b\),求在 \([a,b]\) 中的所有整数中,每个数码(digit)各出现了多少次。

输入格式

仅包含一行两个整数 \(a,b\),含义如上所述。

输出格式

包含一行十个整数,分别表示 \(0\sim 9\) 在 \([a,b]\) 中出现了多少次。

样例 #1

样例输入 #1

1 99

样例输出 #1

9 20 20 20 20 20 20 20 20 20

提示

数据规模与约定

  • 对于 \(30\%\) 的数据,保证 \(a\le b\le10^6\);
  • 对于 \(100\%\) 的数据,保证 \(1\le a\le b\le 10^{12}\)。

求给出的边界 \([a,b]\) 中,每个数码(\(0-9\))出现了多少次。

对于满 \(i\) 位(指第 \(i\) 位可以从 \(0\) 枚举到 \(9\))的数,所有数字出现次数相同。

设 \(f_i\) 是满 \(i\) 位的数每个数字出现的次数,有 \(1-i\) 位的贡献=\(1-(i-1)\)位置的贡献\(\times 10+10^{i-1}\):

\[ \begin{aligned} f_i=10\times f_{i-1}+10^{i-1} \end{aligned} \]

(\(10^{i-1}\) 是因为在第 \(i\) 位置产生贡献的情况下忽略第 \(i\) 位置,\(1-(i-1)\) 位置从全是 \(0\) 枚举到全是 \(9\) 共 \(10^{i-1}\) 的贡献由第 \(i\) 位产生)

考虑统计答案,将上界按位分开,从高到低枚举防漏,\(a_i\) 表示在第 \(i\) 位置的数,分着考虑:

  • \(1-(i-1)\) 位置的贡献,为 \(f_{i-1}\times a_i\)

  • 第 \(i\) 位置的数不是 \(a_i\) 时,不管后面什么数。贡献为 \(fac_{i-1}.\)(\(10\) 的阶乘)

  • 第 \(i\) 位置上的数是 \(a_i\) 时,其贡献是后面的数加上 \(1\) (后面的数全是 \(0\) 也行)

  • 前导 \(0\)。第 \(i\) 位是前道 \(0\) 时,第 \(1-(i-1)\) 位都是 \(0\),减去重复计数答案。

如果还不太明白就看代码注释,自己拿一个数字推一下,我就不推了:

(由于这道题明显递推更加简单所以选择递推)

Miku'sCode
#include<bits/stdc++.h>
using namespace std;

typedef long double llf;
typedef long long intx;
const int maxn=15;

int a[maxn]; 
intx l,r,f[maxn],fac[maxn];
//fac是10的阶乘,数据小于1e12故到13 
intx ans1[maxn],ans2[maxn];

void input(){
	scanf("%lld %lld",&l,&r);
}

void pre(){
//预处理 
	fac[0]=1;
	for(int i=1;i<=13;++i){
		f[i]=f[i-1]*10+fac[i-1];
		fac[i]=(intx)10*fac[i-1];
		cout<<"###"<<i<<' '<<f[i]<<endl;
	}
}

void work(intx n,intx *ans){
//求1-n所有数的数码计数和,放入ans数组 
	intx tmp=n;
	int len=0;
	while(n)	a[++len]=n%10,n=n/10;
	for(int i=len;i>=1;--i){
	//从高位向低位模拟 
		for(int j=0;j<=9;++j)	ans[j]=ans[j]+f[i-1]*a[i];
		//不贴近上界,随便取值
		/*
		简单来说:1-(i-1)位置从0000到9999的某个数的计数是f[i-1]
		到a[i]算是贴近上界,这里加的是 1-(i-1)位置的数 
		*/ 
		for(int j=0;j<a[i];++j)	ans[j]=ans[j]+fac[i-1];
		//贴近上界,取0到上界
		/*
		简单来说
		就是把在第i位从0到上界-1的数的贡献加起来了。 
		*/ 
		tmp=tmp-fac[i-1]*a[i]; 
		ans[a[i]]=ans[a[i]]+tmp+1;
		//将最后的上界上的数贡献加起来
		ans[0]=ans[0]-fac[i-1];
		//若第i位置是前导0,减去重复计数 
	}
}

int main(){
	pre();
	input();
	work(r,ans1);
	work(l-1,ans2);
	for(int i=0;i<=9;++i){
	//计数原理[1-r]-[1-(l-1)]=[l-r] 
		printf("%lld ",(intx)ans1[i]-ans2[i]);
	}
	return 0;
}


标签:10,20,笔记,计数,maxn,dp,数位
From: https://www.cnblogs.com/sonnety-v0cali0d-kksk/p/17596666.html

相关文章

  • [刷题笔记] Luogu P1877 音量调节
    ProblemDescription共\(n\)次操作,每次操作有一个值\(a_i\),同时给定一个初始值\(start\),对于每次操作,可以将值\(k\)加或减\(a_i\)(\(k\)初始=\(start\)),求经过这\(n\)操作后\(k\)的最大值。Solution其实这是一个01背包的变形。这和01背包有何关系呢?回顾一下经典01背包:有......
  • 20230801 数论基础学习笔记
    理论基础中国剩余定理及拓展已知\(x\equiva_i(\bmodp_i\)\),求\(x\bmod\operatorname{lcm}\{p_i\}\)的值。若\(p_i\)互质,那么我们只需要计算\(c_i\)使得\[\prod\limits_{j\nei}\cdotc_i\bmodp_i=1\]然后有\[x=\sum\limits_{i}c_ia_i\prod\limits......
  • DPC WATCHDOG VIOLATION
    蓝屏SmbCo10X64.syshttps://answers.microsoft.com/zh-hans/windows/forum/all/%e6%9c%80%e8%bf%91%e7%94%b5%e8%84%91%e6%80%bb/d228ea4b-3945-4b1c-8c98-b1b3823d0213https://answers.microsoft.com/zh-hans/windows/forum/windows_11-windows_install/%e8%93%9d%e5%b1%8f/......
  • 笔记:KMP的复习
    Record一个重要的字符串算法,这是第三次复习。通过总结我认为之所以某个算法总是忘记,是因为大脑始终没有认可这种算法的逻辑(也就是脑回路)。本篇主要讲解从KMP的应用场景,再到算法知识,以及例题。Main现有两个字符串\(A,B\),求出\(A\)在\(B\)中出现的次数。范围:字符串长度......
  • HC32F460串口波特率设置19200,函数返回ErrorInvalidParameter
    今天,在调试项目的时候,遇到设置串口2波特率为19200的时候,USART_SetBaudrate(M4_USART2,19200)函数返回 ErrorInvalidParameter,导致程序陷入了死循环,配置程序如下:voidUSART2_LIN_Config(void){#ifdefLIN_EN#ifdefHC32_MCUstc_usart_uart_init_tstcInitCfg;......
  • RASP知识学习笔记
    RASPRASP(Runtimeapplicationself-protection)是一种内置或链接到应用程序环境中的安全技术,与应用程序融为一体,实时监测、阻断攻击,使程序自身拥有自我保护的能力。工作原理RASP技术是一种基于服务器的技术,一旦应用程序运行开始时就会激活。而且,所有RASP产品都包含一个运行时监......
  • 关于菜鸡学习RHEL8的一些小笔记--->LVM逻辑卷
    LVM基础概念:LVM()逻辑卷管理器,主要适用于对Linux环境下面磁盘分区的管理机制在真实的场景中,服务器使用的越久,所产生的数据量就会越来越大,导致硬盘本身空间越来越小;这里针对分区来看,如果想要扩大容量,就得重新挂载硬盘,然后去做数据迁移,这样就会直接导致业务停止运行;#这里分区的大小是在......
  • WordPress Qui-Pure V2.4发布纯文本/图文博客主题正式发布!
    主题介绍:Qui-Pure是我开发的第一款主题,纯文本展示博客类型,后台控制是否加载图片/轮播图,页面布局改成图文排版!兼容erphpdown,加入个人中心,由于技术学习来源互联网,WordPress是开源平台,因此主题免费回报大家,希望大家喜欢这款简约至上的主题!主题免费、免费、免费...主题功能:1.......
  • 【学习笔记】记忆化搜索
    记忆化搜索目录前置知识:概念:实现:oiwiki:记忆化搜索建议搭配食用。前置知识:深度优先搜索DFS概念:搜索通常通过递归来实现,但是递归过程中往往有很多结果被重复计算,因此降低了搜索的效率。因此记忆化搜索就是再递归的过程中记录已经遍历过的状态与结果,用到的时候再直接取出......
  • udp接收上位机编程(2)彩色图像
    由于QT上位机只能接收BGR565的图像格式,且只能显示灰度或者RGB888,所以PL2PS的数据必须要变换位置,并使用cvtColor函数进行转换1voidMainWindow::recieve_dis(intudp_index)2{3Matrecv_img_2(img_h_size,img_w_size,CV_8UC2);4Matrecv_img_3(img_h_size,img_......