洛谷传送门
BZOJ传送门
题目描述
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为 2 2 2的正整数被称为windy数。 windy想知道,
在 A A A和 B B B之间,包括 A A A和 B B B,总共有多少个windy数?
输入输出格式
输入格式:
包含两个整数, A B A\ B A B。
输出格式:
一个整数
输入输出样例
输入样例#1:
1 10
输出样例#1:
9
输入样例#2:
25 50
输出样例#2:
20
说明
100 % 100\% 100%的数据,满足 1 ≤ A ≤ B ≤ 2000000000 1 \le A \le B \le 2000000000 1≤A≤B≤2000000000。
解题分析
显然我们可以预处理出一共有 i i i位, 最高位为 j j j的 w i n d y windy windy数个数。 按照套路, 我们只需要得到 [ 1 , l e f − 1 ] [1,lef-1] [1,lef−1]的 w i n d y windy windy数个数和 [ 1 , r i g ] [1,rig] [1,rig]的 w i n d y windy windy数个数即可。现在我们只讨论 [ 1 , k ] [1,k] [1,k]的 w i n d y windy windy数个数。
设 k k k有 m m m位, 最高位为 t t t, 那么我们分以下情况考虑:
- 位数 < m <m <m的情况, 直接累加即可。
- 位数 = m =m =m, 但最高位 < t <t <t的情况, 仍然直接累加。
- 位数 = m =m =m,最高位 = t =t =t的情况, 考虑次高位为 x x x, 直接累加次高位 0 ∼ x − 1 0\sim x-1 0∼x−1的结果, 继续如此计算下去。 注意如果某两位原本的差就 < 2 <2 <2直接 b r e a k break break, 因为我们考虑的是更高位取满的情况。
这样有一个小锅: 因为我们始终累加到当前考虑的最高位的数位 − 1 -1 −1(因为最高位可能取不满), 所以实质上我们的 s o l v e ( n ) solve(n) solve(n)算出来的是 n − 1 n-1 n−1的结果, 预先 + 1 +1 +1即可。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
#define MX 12
template <class T> IN T abs(T a) {return a > 0 ? a : -a;}
ll dp[MX][10];
int buf[MX];
void init()
{
for (R int i = 0; i <= 9; ++i) dp[1][i] = 1;
for (R int i = 2; i <= 10; ++i)
{
for (R int j = 0; j <= 9; ++j)
for (R int k = 0; k <= 9; ++k)
if(abs(j - k) >= 2) dp[i][j] += dp[i - 1][k];
}
}
int solve(R int lim)
{
if(lim == 0) return 0;
int ans = 0, len = 0;
W (lim) buf[++len] = lim % 10, lim /= 10;
for (R int i = len - 1; i; --i)
for (R int j = 1; j <= 9; ++j) ans += dp[i][j];
for (R int i = 1; i < buf[len]; ++i) ans += dp[len][i];
for (R int i = len - 1; i; --i)
{
for (R int j = 0; j < buf[i]; ++j)
if(abs(j - buf[i + 1]) >= 2) ans += dp[i][j];
if(abs(buf[i + 1] - buf[i]) < 2) break;
}
return ans;
}
int main(void)
{
int lef, rig;
init();
scanf("%d%d", &lef, &rig);
printf("%d", solve(rig + 1) - solve(lef));
}