题面
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
思路
1.由于是计算[A,B]间windy数字,那么可以用前缀和思想,统计前A-1个数字中的windy数 数量,再统计前B个windy数 数量,答案就是两者之差。
2.数位DP,用表示数字位数为i且最高位(第一位)数字位j的windy数目,比如表示500~599中有多少windy数.DP方程:,状态转移方程如何构造:假如统计,就是300~399中有多少windy数,这时我们发现只要找到300~399从第二位已经得到的2位数字的windy数字之和,且2位数的最高位和3相差大于等于2.
3.统计答案。[详情见代码及注释]
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long lint;
lint DP[11][10];
void Init(void)
{
for(int i = 0;i <= 9;i++)
{
DP[1][i] = 1;
}
for(int i = 2;i <= 10;i++)
{
for(int j = 0;j <= 9;j++)
{
for(int k = 0;k <= 9;k++)
{
if(abs(j-k) >= 2)
{
DP[i][j] += DP[i-1][k];
}
}
}
}
}
lint L,R;
lint Solve(lint N)
{
lint ans = 0;
int Wei[11] = {0};
int len = 0;
if(N == 0)
{
return 0;
}
while(N)
{
Wei[++len] = N%10;
N/=10;
}
//统计1-(len-1)位数字方案数
for(int i = 1;i < len;i++)
{
for(int j = 1;j <= 9;j++)
{
ans += DP[i][j];
}
}
//统计len位数字
//假如被统计数字最高为4,那么会统计len位数字的最高位为1,2,3,的数字,还剩一部分没有统计
for(int i = 1;i < Wei[len];i++)
{
ans += DP[len][i];
}
//统计零头
//假设N == 4211,这一步需要统计4000-4211中的windy数
for(int i = len-1;i >= 1;i--)
{
for(int j = 0;j < Wei[i];j++)
{
//这里原理同 状态转移方程
if(abs(j-Wei[i+1]) >= 2)
{
ans += DP[i][j];
}
}
//由于前面从len-1位的数字从0开始,如果出现了这个条件,那么以后所有的都不合法
//建议手动模拟
if(abs(Wei[i+1]-Wei[i]) < 2)
{
break;
}
if(i == 1)
{
ans++;
}
}
return ans;
}
int main(void)
{
Init();
lint A,B;
cin >> A >> B;
cout << Solve(B) - Solve(A-1) << endl;
return 0;
}