数位dp学习笔记

数位dp的特点

  • 要求统计满足一定条件的数段数量
  • 这些条件经过转化后可以使用数位的思想去理解和判断
  • 输入会提供数字区间来限制统计
  • 上界非常大

数位dp原理

从最高位向着低位一步一步枚举,记录下会对于后续产生影响的条件

一般在记忆化搜索时记录下是否受范围限制,若有限制则枚举而不记忆化

通过记忆化搜索来完成问题即可

由于数位dp基本不需要优化,所以直接写记忆化一般都是可以的

常见代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,a[],len,dp[][],vis[][];
int dfs(int p,...,bool limit){
	if(!p)return 0/1/...;
	if(!limit&&vis[p][])return dp[p][];
	int res=0;
	for(int i=limit?a[p]:9/1/...;i>=0;i--){
		if(check(...)){
			res+=dfs(p-1,...,limit&(a[p]==i));
		}
	}
	if(!limit){
		vis[p][]=1;
		dp[p][]=res;
	}
	return res;
}
int solve(int x){
	int p=x;
	len=0;
	while(p){
		a[++len]=p%10;
		p/=10;
	}
	return dfs(len,10,1,1);
}
signed main(){
	int l,r;
	cin>>l>>r;
	cout<<solve(r)-solve(l-1);
	return 0;
}

常见问题及其处理:

计数

p为0时,直接返回1

在条件不满足时,直接不进行dfs即可

求和

对于每个数位进行求和时,只用加上这个值

如果是整个数字求和,需要在处理返回值时记录一下返回的值的数量

平方和

由平方和公式可以将数组拆成五部分,分别为需要处理的值,不需要处理的值以及数目

由于最终答案可能较大,在大部分情况下要有模数

每一段的和

得到每一位对于答案的贡献,贡献由所在位置和每一个位置的数量得到

数位dp其它思路

  • 给定一个函数,求函数中满足特殊规则的值,若数学方法无法得出,可以尝试打表找规律,在特殊情况下尝试

  • 通过质因数分解,处理每一位上的乘积问题

总结

在数位dp的题目中,通常只需要去考虑状态怎么设计,需要记录下哪些值,如何转移即可,不需要使用单调队列等优化,处理每一位数之间的复杂问题,这是一个常见的方法,通过枚举数位,一步一步的进行dp

posted @ 2025-11-28 10:03  huhangqi  阅读(0)  评论(0)    收藏  举报
/*
*/