前言
本篇博客目的是给自己总结复习用,而不是给萌新学习用滴。萌新能不能看得懂需要看造化=.=,毕竟数位 dpdpdp 还是有点难理解的。
概括
数位 dpdpdp,是用来解决一些带有数位上的限制的计数问题的。常见的有问区间 [L,R][L, R][L,R] 中满足某种数位限制的数的个数,或者求数对的对数等等,也可以用来求和。一般是用 [0,R][0,R][0,R] 的 值减去 [0,L−1][0, L- 1][0,L−1] 的值。
常常设 dp[pos][sta]dp[pos][sta]dp[pos][sta] 表示从高到低来到了第 pospospos 位,前面的状态为 stastasta 的数的个数。
在 dfsdfsdfs 过程中,会有一个参数 limitlimitlimit,表示当前数位的枚举范围是不是有限制。
只有当前面的每个数位都取到最大值时,limitlimitlimit 才会等于 111。
limitlimitlimit 等于 000 的时候,说明从这一位往后,每个数位都可以取 [0,9][0, 9][0,9],这里产生了大量重复或等价的状态,通过记忆化来压缩起来。
数位 dpdpdp 的时间复杂度为 O(状态数∗转移复杂度)O(状态数 * 转移复杂度)O(状态数∗转移复杂度)。
数位 dpdpdp 的模板
数位 dpdpdp 的 dpdpdp 数组可以分为记录 limitlimitlimit 和不记录的,当统计的是数对的时候,记录 limitlimitlimit 会使复杂度降低。
状态中带有 limitlimitlimit 的
这种 dpdpdp 数组每次都要进行 memsetmemsetmemset,因为每个数的数位限制不同。
状态中不带 limitlimitlimit 的
这种 dpdpdp 数组可以适用于多组数据,因为状态是普遍的,不是针对单独一个限制的。
入门题 [hdu2089]不要62
求 [L,R][L,R][L,R] 中数字中不带 444 和 626262 的数的个数。
dfsdfsdfs 的过程中,传入几个参数:当前到了第几位,前面一位是不是 666,当前数位有没有限制。
#include <bits/stdc++.h>
using namespace std;
int dp[10][2], a[10];
int dfs(int pos, int f1, int f2){
if(!pos) return 1;
if(!f2 && dp[pos][f1] != -1) return dp[pos][f1];
int res = 0, up = f2? a[pos]: 9;
for(int i = 0; i <= up; i++){
if(i == 4 || (f1 && i == 2)) continue;
res += dfs(pos - 1, i == 6, f2 && i == up);
}
if(!f2) dp[pos][f1] = res;
return res;
}
int f(int x){
int tot = 0;
while(x) a[++tot] = x % 10, x /= 10;
return dfs(tot, 0, 1);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
memset(dp, -1, sizeof(dp));
int l, r;
while(cin >> l >> r){
if(!l && !r) break;
cout << f(r) - f(l - 1) << '\n';
}
return 0;
}
[hdu3555] bomb
求 [L,R][L,R][L,R] 中包含 494949 的数的个数。
f1f_1f1 表示上一位是不是 444, f2f_2f2 表示枚举是不是有限制,f3f_3f3 表示前面是否已经出现 494949 了。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
void debug_out(){
cerr << endl;
}
template<typename Head, typename... Tail>
void debug_out(Head H, Tail... T){
cerr << " " << to_string(H);
debug_out(T...);
}
#ifdef local
#define debug(...) cerr<<"["<<#__VA_ARGS__<<"]:",debug_out(__VA_ARGS__)
#else
#define debug(...) 55
#endif
LL dp[22][2][2];
int a[22];
LL dfs(int pos, int f1, int f2, int f3){
//debug(pos, f1, f2, f3);
if(!pos) return f3;
if(!f2 && dp[pos][f1][f3] !=