洛谷P2657 windy数

传送

裸的数位dp

看这个题面,要求相邻两个数字之差至少为2,所以我们记录当前填的数的最后一位

同时要考虑毒瘤的前导0。如果填的数前面都是0,则这一位填0是合法的。

emmm具体的看代码叭

#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define pa pair<int,int>
typedef long long ll;
using namespace std;
const int inf=214748364;
inline ll read()
{
    char ch=getchar();
    ll x=0;bool f=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    }
    return f?-x:x;
}
ll a,b,f[15][10],li[15],t;//li[i]表示在顶上界的时候第i为最大是多少
void ma(ll r)
{
    t=0;
    memset(li,0,sizeof(li));
    while(r)
    {
        li[++t]=r%10;
        r/=10;
    }
    
}
ll sol(int now,int lst,bool lim,bool al)//now记录填到第now位,lst是上一位填的数,lim表示是否顶上界,al表示是否前面都是0
{
    if(now==0)return 1;
    if(!al&&!lim&&f[now][lst]!=-1)return f[now][lst];
    int up=lim?li[now]:9;
    ll rtn=0;
    for(int i=0;i<=up;i++)
    {
        if((abs(lst-i)<2)&&!al)continue;
        rtn+=sol(now-1,i,(lim&&(i==up)),((i==0)&&al));
    }
    if(!al&&!lim)f[now][lst]=rtn;
    return rtn;
}

int main()
{
    memset(f,-1,sizeof(f));
    a=read();b=read();
    ma(b);//先对[1,b]搞一遍
    ll ans=sol(t,0,1,1);
    ma(a-1);//再对[1,a-1]搞一遍
    ll an=sol(t,0,1,1);
    ans-=an;
    printf("%d",ans);
}

 

posted @ 2019-08-15 08:52  千载煜  阅读(191)  评论(0编辑  收藏  举报