oneman233

P2657 [SCOI2009]windy数(数位dp)

题面仍然非常亲民:

windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?

这道题跟数字计数有点差别,参数比较少,传三个参数下去就行:

**
len:当前搜索剩余的长度
last:上一位数字是什么
up:前面是否有数字达到了枚举上限
**

上一位数字的初始值传一个-2进去即可
注意样例当中0这个数字不合法,全0是不可以接受的
返回答案和记忆化的时候要注意这一点

枚举方向仍然是从右向左
如果长度为0返回1即可
并且要保证任意两位绝对值之差大于等于2

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=25;

ll a,b;
int dp[N][N],num[N];

int dfs(int len,int last,int up)
//from right to left
{
	if(len==0) return 1;
	if(!up&&last>=0&&dp[len][last]!=-1)
		return dp[len][last];
	int p,cnt=0,mx=(up?num[len]:9);
	for(int i=0;i<=mx;++i)
	{
		if(abs(i-last)<2) continue;
		if(i==0&&last==-2) p=-2;
		else p=i;
		cnt+=dfs(len-1,p,up&&i==mx);
	}
	if(!up&&last>=0) dp[len][last]=cnt;
	return cnt;
}

void gao()
{
	int k=0;
	a--;
	while(a)
	{
		num[++k]=a%10;
		//start from 1
		a/=10;
	}
	memset(dp,-1,sizeof(dp));
	int left=dfs(k,-2,1);
	k=0;
	while(b)
	{
		num[++k]=b%10;
		b/=10;
	}
	memset(dp,-1,sizeof(dp));
	int right=dfs(k,-2,1);
	printf("%d\n",right-left);
}

int main()
{
	scanf("%lld%lld",&a,&b);
	gao();
	return 0;
}

posted on 2019-11-08 16:26  oneman233  阅读(134)  评论(0编辑  收藏  举报

导航