P2657 [SCOI2009] windy 数(数位DP)
题目背景
windy 定义了一种 windy 数。
题目描述
不含前导零且相邻两个数字之差至少为 22 的正整数被称为 windy 数。windy 想知道,在 aa 和 bb 之间,包括 aa 和 bb ,总共有多少个 windy 数?
输入格式
输入只有一行两个整数,分别表示 aa 和 bb。
输出格式
输出一行一个整数表示答案。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
typedef long long ll;
ll f[20][20];//f(i,j)表示搜到第i位,前一位是j的合法方案数
int a[20],len;
ll L,R;
ll dfs (int pos,int pre,int st,int limit) {
//pos表示当前位置
//pre表示前一位数
//st表示前面是否全为0
//limit表示最高位限制
if (pos>len) return 1;//dfs终点
if (!limit&&f[pos][pre]!=-1) return f[pos][pre];
//没有最高位限制,并且已经搜过了
ll ans=0;
ll k=limit?a[len-pos+1]:9;//当前位最大数字
for (int i=0;i<=k;i++){
//从0枚举最大数字
if (abs(i-pre)<2) continue;
//不符合题意,继续
if (st&&i==0) {
//如果前面全为0,下一位随意
ans+=dfs(pos+1,-2,1,limit&&i==k);
//如果有前导0,下一位随意
}
else {
//如果没有前导0,继续按部就班的搜
ans+=dfs(pos+1,i,0,limit&&i==k);
}
}
if (!limit&&!st) {
//没有最高位限制且没有前导0时记录结果
f[pos][pre]=ans;
}
return ans;
}
ll solve (ll x) {
len=0;
while (x) a[++len]=x%10,x/=10;
memset(f,-1,sizeof(f));
return dfs(1,-2,1,1);
}
int main () {
cin>>L>>R;
cout<<solve(R)-solve(L-1);
}