算法——数位dp

1 篇文章 0 订阅
  • 注释:本文的区间都是闭区间

  • LDU数位dp练习

  • 讲解视频
    00 : 00 − −   \small 00:00 --~ 00:00 数位 d p \small dp dp原理讲解
    02 : 50 − −   \small 02:50 --~ 02:50 “度的数量”思路讲解
    21 : 40 − −   \small 21:40 --~ 21:40 “度的数量”代码讲解
    36 : 20 − −   \small 36:20 --~ 36:20 “数字游戏”思路讲解
    48 : 00 − −   \small 48:00 --~ 48:00 “数字游戏”代码讲解
    56 : 50 − −   \small 56:50 --~ 56:50 “Windy 数”思路讲解
    65 : 00 − −   \small 65:00 --~ 65:00 “Windy 数”代码讲解
    83 : 30 − −   \small 83:30 --~ 83:30 “数字游戏II”思路讲解
    94 : 20 − −   \small 94:20 --~ 94:20 “数字游戏II”代码讲解
    104 : 10 − −   \small 104:10 --~ 104:10 “不要62”思路讲解
    115 : 10 − −   \small 115:10 --~ 115:10 “不要62”代码讲解
    127 : 40 − −   \small 127:40 --~ 127:40 “恨 7 不成妻”思路讲解
    145 : 10 − −   \small 145:10 --~ 145:10 “恨 7 不成妻”代码讲解

  • 数位dp解决的问题:求出给定区间 [ L , R ] \small [L,R] [L,R],符合函数 f ( x ) \small f(x) f(x)的个数。
    例:
    f ( x ) \small f(x) f(x):不降数—— x \small x x必须满足从左到右各位数字成小于等于的关系。如 123 \small 123 123 446 \small446 446
    L = 1 \small L=1 L=1 , \small , , R = 19 \small R=19 R=19
    答案: 18 \small 18 18
    解释:只有 10 \small 10 10不是不降数,其余的数都是不降数,故答案为 18 \small 18 18

  • 数位dp的技巧
    1 、 1、 1 d p ( L , R ) = d p ( 0 , R ) − d p ( 0 , L − 1 ) \small dp(L,R)=dp(0,R)-dp(0,L-1) dp(L,R)=dp(0,R)dp(0,L1
    对于 [ L , R ] \small [L,R] [L,R]区间问题,我们一般把他转化为两次数位 d p \small dp dp,即找 [ 0 , R ] \small [0,R] [0,R] [ 0 , L − 1 ] \small [0,L-1] [0,L1]两段,再将结果相减就得到了我们需要的 [ L , R ] \small [L,R] [L,R]
    例:通过前缀和求区间和
    2 、 2、 2画树

  • 模板

#include<vector>
#include<iostream>
using namespace std;

const int N = 100;

int f[N][N];
int u[N];

//根据题目要求来预处理f[i][j]
void init() {

}
//计算[0,n]符合f(x)的个数
int dp(int n) {
	//如果L可以取到0的话,特判-1
	if (n == -1) return 0;
	//特判0
	if (n == 0) return 0 / 1;

	//用于把每位的数字提取出来
	vector<int> vt;
	while (n) vt.push_back(n % 10), n /= 10;

	//res记录返回值,last保留前缀的信息
	int res = 0, last = 0;
	for (int i = vt.size() - 1; i >= 0; i--) {
		//第一种放法
		for (int j = 0; j < vt[i]; j++) {
			if (true) res += f[][];
		}
		//第二种放法就是vt[i]本身,特判vt[i]是否和法,不合法直接退出就好
		if (false) break;
	}

	//返回答案
	return res;
}
int main() {

	//预处理需要的数据
	init();

	int l, r;
	while (cin >> l >> r) {
		//技巧一
		cout << dp(r) - dp(l - 1) << endl;
	}
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值