数位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

浙公网安备 33010602011771号