题目描述
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
输入输出格式
输入格式:
包含两个整数,A B。
输出格式:
一个整数
思路
1.DP到第几位(ws),维护方法,开始时设为上限数的位数,然后每次向下枚举时-1s,当ws为0时输出sum并且退出枚举即可。
2.DP中对获得的结果的记录(sum),维护方法,开始时设为0,当ws为1时判断此数是否为0,不是的话就+1s
3.前导零(zero),维护方法,开始时设为0(有前导零),后面枚举时当当前位置不为0或枚举当前位前前导零即不为0时设为1(无前导零),其余时刻设为0即可。
4,上一位数字(pr),维护方法,开始时设为0,后面直接传下去即可。
5,枚举上限(rua)维护方法,这个没什么说的,如果枚举当前位前就没有达到上限或者是枚举的数字不是这一位上限时设为0(未达到上限),其余设为1(达到上限)即可。
顺便强调一点,memset一定要在每次DP前都要做,不做的话会爆零。
代码
#include <cstdio>
#include <cstdlib>
int num[2][11];
int iEnd[2];
void GetNum(int x, int out[], int& sz)
{
if (x == 0)
{
sz = 1;
return;
}
int temp(x);
sz = 0;
while (temp)
{
temp /= 10;
++sz;
}
for (int i(0); i != sz; ++i)
{
out[i] = x % 10;
x /= 10;
}
for (int i(0); i != sz / 2; ++i)
{
out[i] ^= out[sz - i - 1] ^= out[i] ^= out[sz - i - 1];
}
}
int a, b;
bool bVis[11][11][2];
int dp[11][11][2];
inline int min(int a, int b) { return a < b ? a : b; }
inline int max(int a, int b) { return a > b ? a : b; }
inline int abs(int a) { return a < 0 ? -a : a; }
int dfs(int front, int pos, bool limit, bool forward_zero, int *num)
{
if (!limit && bVis[front][pos][forward_zero]) return dp[front][pos][forward_zero];
if (pos == 0) return 1;
if (limit)
{
int ret(0);
for (int i(0); i < num[0]; ++i)
{
if (abs(i - front) >= 2 || forward_zero)
ret += dfs(i, pos - 1, false, (forward_zero & !i), num + 1);
}
if (abs(num[0] - front) >= 2 || forward_zero) ret += dfs(num[0], pos - 1, true, (forward_zero & !num[0]), num + 1);
return ret;
}
else
{
bVis[front][pos][forward_zero] = true;
int& state(dp[front][pos][forward_zero]);
for (int i(0); i <= 9; ++i)
{
if (abs(i - front) >= 2 || forward_zero)
state += dfs(i, pos - 1, false, (forward_zero & !i), num + 1);
}
return state;
}
}
int main()
{
scanf("%d%d", &a, &b);
--a;
GetNum(a, num[0], iEnd[0]);
GetNum(b, num[1], iEnd[1]);
int front(dfs(0, iEnd[0], true, true, num[0]));
int last(dfs(0, iEnd[1], true, true, num[1]));
printf("%d\n", last - front);
return 0;
}