数位 dp,但是做题笔记
2024-10-20 05:47:12
这玩意儿还要学自己推不出来的 SX 是屑。
数位 dp,顾名思义,是根据数位做 dp,每个数位每个数位转移,炒个例子 windy 数。
求 \([l, r]\),我们改成求 \(1\sim r\) 与 \(1\sim (l - 1)\) 最后二者相减。那么我们的问题就成了求 \(1\sim k\) 的 windy 数。运用 dp,数位 dp 每次从最高位往最低位填数,首先我们要知道填到第几位 \(i\)。由于是填数,但是填的数字不能超过限定范围,因此我们加一维记录前 \(i - 1\) 位是否与 \(k\) 的前 \(i - 1\) 位相同,如果相同则 \(i\) 位最多只能填到 \(k\) 的第 \(i\) 位否则能填到 \(9\),同时我们还要记录 \(i\) 是不是前导 0。
通常的数位 dp 的状态是个三元组,\(f_{i, 0/1, 0/1}\) 代表填到了 \(i\) 位与 \(k\) 的前 \(i - 1\) 位是否一致,\(i\) 是否是前导 \(0\)。这是个板子(笑)。这题我们还要加入一个 \(last\) 代表 \(i\) 的下一位填的是什么。因此我们的状态是 \(f_{i, last, 0/1, 0/1}\)。
转移应该很显然。。。用记搜,因为用迭代写起来很难受。
//SIXIANG
#include <iostream>
#include <cstring>
#define int long long
#define MAXN 100000
#define QWQ cout << "QWQ" << endl;
using namespace std;
int arr[MAXN + 10], t = 0;
void divide(int x) {
do {
arr[++t] = x % 10;
x /= 10;
} while(x);
}
int f[100][15][2][2];
int Abs(int x) {
if(x < 0) return -x;
else return x;
}
//填到第 i 位上个数是 last 前 (i - 1) 位是否与 k 相同
int windy(int i, int last, int fa, int ze) {
if(!i) return 1;
if(f[i][last][fa][ze] != -1) return f[i][last][fa][ze];
int limit = ((fa) ? arr[i] : 9);
int rest = 0;
for(int p = 0; p <= limit; p++)
if(Abs(p - last) >= 2 || ze)
rest += windy(i - 1, p, ((p == arr[i]) & fa), (ze & (!p)));
f[i][last][fa][ze] = rest;
return rest;
}
int work(int k) {
memset(f, -1, sizeof(f));
memset(arr, 0, sizeof(arr));
t = 0;
divide(k);
return windy(t, 11, 1, 1);
}
signed main() {
int l, r; cin >> l >> r;
cout << work(r) - work(l - 1) << endl;
}
最新文章
- Linux下的压缩和解压缩命令——bzip2/bunzip2
- shell 问题解决
- 正确的前端传后台json方式
- Jetty 发布web服务
- List.Sort用法
- [转]快速构建App界面的框架(●&#39;◡&#39;●) -----SalutJs
- 总结 output 用法
- java.util.concurrent并发包诸类概览
- VS2015预览版中的C#6.0 新功能(三)
- setinterval
- Apache与Nginx优缺点比较
- 设计模式:Prototype 原型模式 - 同学你抄过别人的作业么?-clone()方法的使用
- .Net Core 之 MSBuild 介绍
- 如何解决chrome 等浏览器不支持本地ajax请求的问题
- Dom的增删查改以及常用事件
- 从parcel.js打包出错,到拥抱nvm
- 什么是MVC ?
- c# linq 汇总
- VUE2.0 饿了吗视频学习笔记(三):VUE2.0取消了v-link
- python3之深浅拷贝