Loading

洛谷P2657 [SCOI2009] windy 数(数位DP)

题目背景

windy 定义了一种 windy 数。

题目描述

不含前导零且相邻两个数字之差至少为 22 的正整数被称为 windy 数。windy 想知道,在 aa和 bb 之间,包括 aa 和 bb ,总共有多少个 windy 数?

输入格式

输入只有一行两个整数,分别表示 aa 和 bb

输出格式

输出一行一个整数表示答案。

输入输出样例

输入 #1复制

1 10

输出 #1复制

9

输入 #2复制

25 50

输出 #2复制

20

参考https://www.luogu.com.cn/blog/HONOUR/solution-p2657

从0开始数位dp。

#include <bits/stdc++.h>
using namespace std;
int a, b, num[33], len;
int dp[33][33][2][2];
int dfs(int len, int last, int flag, int zero) {//参数为从高到低当前处理到第几位 范围是1到len last是上一位的数 flag表示之前的部分是否紧贴边界 zero表示是否有前导0
	if(len == 0) return 1;//实际上可以在下面代码中特判 比如len == 1且满足条件 则直接ans += 1
	if(dp[len][last][flag][zero] != -1) return dp[len][last][flag][zero];
	int ans = 0;
	for(int i = 0; i <= 9; i++) {
		if((abs(i - last) >= 2 || zero) && ((flag && i <= num[len]) || !flag)) {//当前面全为0的时候这一位不用管相差多少
			ans += dfs(len - 1, i, flag && (i == num[len]), zero && (i == 0));
		}
	}
	return (dp[len][last][flag][zero] = ans);
}
int calc(int x) {
	memset(num, 0, sizeof(num));
	len = 1;
	while(x) {
		int now = x % 10;
		x /= 10;
		num[len] = now;
		len++;
	}
	for(int i = 0; i < 32; i++) {
		for(int j = 0; j < 32; j++) {
			for(int k = 0; k < 2; k++) {
				for(int w = 0; w < 2; w++) {
					dp[i][j][k][w] = -1;
				}
			}
		}
	}
	return dfs(len, 11, 1, 1);
}
int main() {
	cin >> a >> b;
	cout << calc(b) - calc(a - 1);
	return 0;
}
posted @ 2021-04-28 16:19  脂环  阅读(69)  评论(0编辑  收藏  举报