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);
}
posted @ 2021-03-28 22:28  zlc0405  阅读(73)  评论(0编辑  收藏  举报