windy数(数位dp)

https://www.luogu.com.cn/blog/virus2017/shuweidp
https://www.luogu.com.cn/problem/P2657

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
const int maxn = 200100;

ll dp[20][10];   //dp[i][j]为当前在 i 位,前一位的数是 j 时的方案数。
ll num[20];

ll dfs(int n,bool lead,bool limit,int pre)   //当前位  前导0标记 位限制 前一位数 
{
    if(n<0) return 1;
    if(!limit && !lead && dp[n][pre]!=-1) return dp[n][pre];
    ll ans=0;
    int up=limit?num[n]:9;
    for(int i=0;i<=up;i++)
    {
        if(!lead &&abs(pre-i)<2)    continue;     //无前导0,并且相邻两数小于2 直接遍历下一个
        ans+=dfs(n-1,lead&&i==0,limit&&i==up,i);  //有前导0标记并且当前遍历位为0,前导0传递下去
    }                                             //有限制标志并且当前遍历位到了最大值,传递限制
    if(!limit&&!lead) dp[n][pre]=ans;         //无限制,记忆化
    return ans;
} 

ll solve(ll n)
{
    int len=0;
    while(n)
    {
        num[len++]=n%10;
        n/=10;
    }
    return dfs(len-1,1,1,0);
}

int main()
{
    ll a,b;
    memset(dp,-1,sizeof(dp));
    while(scanf("%lld%lld",&a,&b)!=EOF)
    {
        printf("%lld\n",solve(b)-solve(a-1));
    }
    return 0;
}
posted @ 2019-12-03 20:40  chilkings  阅读(159)  评论(0编辑  收藏  举报