[SCOI2009] windy数 数位DP

时间:2021-11-12 09:28:30

windy数

题面 P2657 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;
}