题目传送门
#include <bits/stdc++.h>
using namespace std;
const int N = 12;//因为n<=m<=1e9 ,所以数位最多是9,开12肯定够
int a[N]; //数位分离的数组
//f[pos][st]表示当前第pos位,这里st只需要去0和1两种状态就可以了,不是6的情况可视为同种,不会影响计数。
int f[N][2];
/**
* 功能:
* @param pos 第pos位
* @param pre 前一位的数字
* @param st pre=6?st=1:st=0,这样就把“不受限情况下,前一位是6或不是6的都记忆化存储起来”
* 现在的理解就是:按集合划分的思想,将位置是pos,前位是6的所有可能存储起来,
* 把前位不是6的所有可能也存储起来,方便再次使用时直接提供
* @param limit 是不是贴上界
* @return
*/
int dfs(int pos, int pre, int st, bool limit) {
if (pos == -1) return 1;//数组下标从0开始,从前向后搜索,所以pos=-1表示完成了所有搜索
if (!limit && f[pos][st] != -1) return f[pos][st];//如果可以利用记忆化结果的话
int up = limit ? a[pos] : 9; //贴上界:a[pos];不贴上界:9
int res = 0; //符合当前条件的运算结果
for (int i = 0; i <= up; i++) { //遍历当前位的所有可能选择数字
//下面两句是题目要求
if (pre == 6 && i == 2)continue;//如果前面数字是6,当前数字是2,那么不能计数
if (i == 4) continue; //4也不要
//将下一数位计算的结果加到当前数位结果中来
res += dfs(pos - 1, i, i == 6, limit && i == a[pos]);
}
//如果不受限制,则记录下来提供下次使用;如果受限制,则一把一利索
return (!limit) ? f[pos][st] = res : res;
}
int calc(int x) {
//数位分离
int pos = 0;
while (x) {
a[pos++] = x % 10;
x /= 10;
}
//调用dfs返回0~x之内符合条件的数字个数
return dfs(pos - 1, -1, 0, true);
}
int main() {
int l, r;
//初始化
memset(f, -1, sizeof f);
while (cin >> l >> r && l + r) //当输入一行为“0 0”时,表示输入结束
printf("%d\n", calc(r) - calc(l - 1));
return 0;
}