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;
}