[BZOJ1026] [洛谷P2657] [SCOI2009]windy数 数位DP
题目描述
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
输入格式
包含两个整数,A B。
输出格式
一个整数
输入输出样例
输入 #1
1 10
输出 #1
9
输入 #2
25 50
输出 #2
20
说明/提示
100%的数据,满足 \(1 <= A <= B <= 2000000000\) 。
题解
数位DP
设\(f[i][j]\)表示 \(i\) 位数,最高位为 \(j\)的符合条件的数的个数。
则$ f[i][j]=\sum_{|j−k|≤2}f[i−1][k] $。
预处理\(f\)数组后进行数位DP。
先填充位数不满的,再由高位向低位将此位不满的加入答案。
且若当前位于上一位数产生冲突导致不会再有满足条件的数时,跳出循环。
转换询问区间为\([1, n)\)则更易简单处理。
code
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
LL f[50][20], bit[50], a, b;
inline int ab(int x) { return x > 0 ? x : -x; }
void init() {
bit[0] = 1; bit[1] = 10;
for(int i = 0;i <= 9;i ++) f[1][i] = 1;
for(int i = 2;i <= 20;i ++) {
bit[i] = bit[i-1] * 10;
for(int j = 0;j <= 9;j ++) {
for(int k = 0;k <= 9;k ++) {
if(ab(j-k) >= 2) f[i][j] += f[i-1][k];
}
}
}
}
LL calc(int x) {
LL pos, di = 1, res = 0, last = -1;
for(pos = 1;bit[pos] <= x;pos ++) {
for(int j = 1;j <= 9;j ++) {
res += f[pos][j];
}
}
for( ; pos ;pos --) {
int now = (x / bit[pos - 1]) % 10;
for(int j = di;j < now;j ++) {
if(ab(j-last) >= 2) res += f[pos][j];
}
if(ab(now-last) < 2) break;
di = 0; last = now;
}
return res;
}
int main() {
init();
cin >> a >> b;
cout << calc(b + 1) - calc(a) << endl;
return 0;
}
作者:Paranoid丶离殇
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。