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; }