#include<bits/stdc++.h>
using namespace std;
#define int long long
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;
#define endl '\n'
#define io ios::sync_with_stdio(false)
#define tie cin.tie(0),cout.tie(0)
#define MOD 998244353
#define inf 0x3f3f3f3f3f
#define maxn 1000006
//因为有10个数字 这里我们取11位的dp
/* i-1解释:
在动态规划数组中的转移:dp[i][j] 表示位数为 i 且从右往左数第 i 位数字为 j 的 Windy 数的个数。dp[i][j] += dp[i - 1][k] 意味着将位数为 i - 1 且第 i - 1 位数字为 k 的 Windy 数的个数,累加到位数为 i 且第 i 位数字为 j 的 Windy 数的个数上。这是因为在构建位数为 i 的 Windy 数时,需要考虑在位数为 i - 1 的 Windy 数的基础上,在更高一位(即第 i 位)添加数字 j 的情况。例如,当计算三位数的 Windy 数时,要基于已经计算出的两位数的 Windy 数情况来进行。
在数字位数上的转移:从数字的实际意义角度,i - 1 代表当前位数 i 的前一位。比如 i 为 3 时表示三位数,i - 1 就是 2,表示两位数。在循环过程中,先确定第 i 位(从右往左)的数字 j,然后通过内层循环遍历第 i - 1 位可能的数字 k,检查 k 和 j 的差值是否满足 Windy 数的条件(abs(k - j) >= 2),如果满足,就将 dp[i - 1][k] 累加到 dp[i][j],相当于把满足条件的前一位数字为 k 的 i - 1 位 Windy 数的数量,转移到了当前第 i 位数字为 j 的情况上,以此来统计位数为 i 的 Windy 数中第 i 位为 j 的个数。
*/
int dp[11][11];
void init(){
//当位数为1,取得数字可以为0~9,算作一个windy数,从最后往最前面推的
for(int i=0;i<=9;i++) dp[1][i]=1;
for(int i=2;i<11;i++){//遍历位数,直到第10位
for(int j=0;j<=9;j++){//对于第j位,我都可以选择0~9来补充,此时不考虑前导0,因为对于j=0后面会进行dp转移,对于当前位数字j,遍历下一位(即第i - 1位)可能的数字k(0到9)
for(int k=0;k<=9;k++){//表示j的后一位可以选择的数字
if(abs(k-j)>=2) dp[i][j]+=dp[i-1][k];
}
}
}
};
int dps(int m){
int res=0;//初始答案
int cnt=0;//数字位数
vector<int>a(11);//提取每个位数
while(m>0) a[++cnt]=m%10,m/=10;//a数组存储的每个位数,从最低位到最高位 符合条件
int last=-1;
//答案是cnt位的
for(int i=cnt;i>=1;i--){//i提取的是第几位数,最高是因为方便后续break _____不断更新每个位可能存在的答案
int now=a[i];//表示当前的数字
for(int j=(cnt==i);j<now;j++){
if(abs(j-last)>=2) res+=dp[i][j];//遍历,因为小于now的数字可能存在windy数
}
if(abs(now-last)<2) break;//假如是12553,遍历到2的时候发现2-1=1,此时小于2,那么对于12000,121..,120..都不是windy数了
last=now;//假如是,那么更新last为上一位的数字
if(i==1) res++;//单独最后一位
}
for(int i=1;i<cnt;i++){
for(int j=1;j<=9;j++){
res+=dp[i][j];
}
}
return res;
}
signed main(){
io,tie;
init();
int n,m;cin>>n>>m;
//进行转移
cout<<dps(m)-dps(n-1);
return 0;
}