[SCOI2009] windy数 数位DP
windy数
比较简单的数位DP。但是需要注意此题与[CQOI2016]手机号码不一样,数的位数长度不定,另外根据样例1可知前一数位为前导0时也满足条件,所以要再添加一个上一位是否为前导零标记。
#include <iostream>
#include <cstring>
#define ll long long
#define ABS(x) ((x)<0?(-(x)):(x))
#define DP dp[p][pre][limted][flag]
using namespace std;
int num[11];
ll dp[11][10][2][2];
ll solve(int p, int pre, bool limted, bool flag){
if(p<=0) return !flag; //windy必须是正整数,0不是
if(DP!=-1) return DP;
int mxnum=(limted?num[p]:9);
ll ans=0;
for(int i=mxnum;i>=0;--i)
if(flag||ABS(i-pre)>=2) ans+=solve(p-1, i, limted&&i==num[p], flag&&i==0); //当前一数位为前导0时也满足条件
return DP=ans;
}
ll work(ll x){
if(x<=0) return 0;
ll ans=0;
memset(dp, -1, sizeof(dp));
int len;
for(len=0;x;x/=10) num[++len]=x%10;
for(int i=num[len];i>=0;i--)
ans+=solve(len-1, i, i==num[len], i==0);
return ans;
}
int main(){
ll l,r;
cin>>l>>r;
cout<<work(r)-work(l-1)<<endl;
return 0;
}