洛谷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); }