【题目描述】
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
【输入格式】
一行A,B
【输出格式】
一行,表示
[
A
,
B
]
[A,B]
[A,B]内windy数个数。
S a m p l e I n p u t Sample~~Input Sample Input
25 50
S a m p l e O u t p u t Sample~~Output Sample Output
20
【题意分析】
数位dp,采用前缀和的方式求出答案
a
n
s
=
f
(
R
+
1
)
−
f
(
L
)
ans=f(R+1)-f(L)
ans=f(R+1)−f(L) (若
f
(
R
)
−
f
(
L
−
1
)
f(R)-f(L-1)
f(R)−f(L−1),则L若是windy数,就不会被统计)
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示前
i
i
i位,而且最高位为
j
j
j的方案数。
显而易见
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]为保证
∣
j
−
k
∣
≤
2
|j-k|\leq2
∣j−k∣≤2的
d
p
[
i
−
1
]
[
k
]
总
和
dp[i-1][k]总和
dp[i−1][k]总和
剩下的就简单了
Code:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cmath>
#include <algorithm>
#define rep(x,y,z) for (register int x = y; x <= z; x++)
#define per(x,y,z) for (register int x = y; x >= z; x--)
#define MAXN 20
using namespace std;
int a[MAXN], dp[MAXN][MAXN], L, R;
//work (x)求出小于等于x的windy数
int work (int x) {
memset (a, 0, sizeof (a)); int ans = 0, len = 0;
//一定要初始化
while (x) a[++len] = x % 10, x /= 10;
//把数x放进数组a
rep (i, 1, a[len] - 1) ans += dp[len][i];//位数等于len但是最高位比a[len]小的windy数
rep (i, 1, len - 1) rep (j, 1, 9) ans += dp[i][j];//位数小于len的windy数
per (i, len - 1, 1) {//i从高位向下枚举,j是第i位的数
rep (j, 0, a[i] - 1) if (abs (j-a[i+1]) >= 2) ans += dp[i][j];//累加满足条件的数
if (abs (a[i]-a[i+1]) < 2) break;//不符条件跳出
}
return ans;
}
int main () {
scanf ("%d%d", &L, &R);
rep (i, 0, 9) dp[1][i] = 1;
rep (i, 2, 10) rep (j, 0, 9) rep (k, 0, 9) if (abs (j-k) >= 2) dp[i][j] += dp[i-1][k];
//预处理统计出dp数组
printf ("%d", work (R+1) - work (L));
//输出答案
return 0;
}