题目描述
Windy 定义了一种 Windy 数:不含前导零且相邻两个数字之差至少为 2 的正整数被称为 Windy 数。
Windy 想知道,在 A 和 B 之间,包括 A 和 B,总共有多少个 Windy 数?
数据范围
$1≤A≤B≤2×10^9$
样例
输入
1 10
输入
9
数位Dp
假设我们当前枚举到第i
位(设共有n
位),且第i
位上的数字为x
,那么对于答案中第i
位数字j
来说,有两类:
-
1.0~x-1 (如果第i位是最高位,这里是1~x-1)
括号中提到的1~x-1后面会解释 ,我们用last
记录上一位的数字,然后枚举j
,如果abs(j-last) >= 2
就累加答案,res += f[i+1][j]
; -
2.x
不需要枚举j
,last = x
,再枚举之后的数位即可
上述做完之后,由于上面的答案都是n
位的,对于数位个数低于n
的,再累加到答案中就行了
f数组的处理
f[i][j]
表示一共有i
位,且最高位数字为j
的满足windy数定义的数的个数
状态转移: 因为第i
位是j
已经确定,考虑第i-1
位,设第i-1
位数字为k
,那么根据windy数定义只要abs(k-j) >= 2
就可以转移过来
$ f[i][j] = \sum_{k=0}^{9}if(abs(k-j)>=2) f[i-1][k] $
关于前导0
上面提到了枚举的第i
位是最高位,那么不能填0
,这里解释一下,如果我们填0
,那么答案就会加上f[i+1][0],,举这样一个例子,
对于数字13
,他是满足windy数定义的,那么加上前导0之后的013
就不会被f[3][0]
加进去,原因就是abs(0-1)<2
,这样就导致答案漏掉。
C++ 代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 11;
int f[N][N]; //f[i][j] 表示一共有i位,且最高为是数字j的满足wingy数定义的数的个数
void init(){
for(int i = 0; i<=9; i++) f[1][i] = 1;
for(int i = 2; i<=9; i++)
for(int j = 0; j<=9; j++)
for(int k = 0; k<=9; k++)
if(abs(k-j)>=2) f[i][j] += f[i-1][k];
}
int dp(int n){
int res = 0,last = -10;
vector<int> a;
while(n)a.push_back(n%10),n/=10;
int len = a.size()-1;
//答案是a.size()位的
for(int i =len; i>=0; --i){
int x = a[i];
for(int j = (i==len); j<x; ++j) //最高位从1开始
if(abs(j-last)>=2) res += f[i+1][j];
if(abs(x-last)<2) break; //不满足定义,直接break
last = x;
if(!i) res ++;
}
//答案小于a.size()位的
for(int i = 1; i<=len; i++)
for(int j = 1; j<=9; j++)
res += f[i][j];
return res;
}
int main()
{
init();
int l,r;
cin>>l>>r;
cout<<dp(r)-dp(l-1);
return 0;
}
改成这样可以过
#include [HTML_REMOVED]
#include [HTML_REMOVED]
#include [HTML_REMOVED]
#include [HTML_REMOVED]
#include [HTML_REMOVED]
using namespace std;
const int N = 35;
int f[N][N];
void init()
{
for(int i = 0; i <= 9; i)
f[1][i] = 1;
for(int i = 2; i < N; i)
{
for(int j = 0; j <= 9; j)
{
for(int k = 0; k <= 9; k)
{
if(abs(k - j) >= 2)
f[i][j] += f[i - 1][k];
}
}
}
}
int dp(int n)
{
if(n == 0)
return 0;
int res = 0;
int last = -10;
vector[HTML_REMOVED] nums;
while(n)
nums.push_back(n % 10), n /= 10;
for(int i = nums.size() - 1; i >= 0; i–)
{
int x = nums[i];
for(int j = (i == nums.size() - 1); j < x; j++)
if(abs(j - last) >= 2)
res += f[i+1][j];
}
int main()
{
init();
int l, r;
cin >> l >> r;
cout << dp(r) - dp(l - 1) << endl;
return 0;
}
代码错了
初始化的问题,数组开小了,同时init里的i<=9小了
666,前导零的问题总结的很棒
%%%
%%%
for(int i = 2; i<=N; i++) 不能等于,数组就开了N位,最大就N-1