送分了QAQ
送分了QAQ
题目大意:
如果一个数字内部包含了4或者38,则称该数字不合法,给定一个区间[n,m] ,求出区间内所有的不合法数字。
分析:
首先给定三个状态,分别用0, 1, 2表示,0状态表示在该位之前没有出现过4 or 38 ,1表示在此之前没出现过4or38并且当前位的值为3,2表示当前位的值为4,或者当前位值为8,并且上一位的值为3。我们通过高位通过递归向低位传递,具体转移见代码,但这里还有个flag,这个标记代表的是否会出现限制。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int f[19][3]; //f[i][j]代表在第i位状态为j的时候的值
int a[19]; //存储一个数n每个位上的值
int dp(int pos, int st, int flag){
//flag这里表示当前是否能够直接返回值,也就是前pos-1位是否和原数不同,如果相同则代表该位受到限制,应该继续递归求解,不同则不受限制,如果前面算过了,可直接返回。
if (pos == 0) return st == 2;
if (flag && f[pos][st] != -1) return f[pos][st]; //如果不受限制,并且当前状态有值,则返回
int mx = flag ? 9 : a[pos]; //限制条件
int ans = 0;
for (int i = 0; i <= mx; ++i){
if (st == 2 || (st == 1 && i == 8) || i == 4){
ans += dp(pos - 1, 2, flag || i < mx);
}else if (i == 3){
ans += dp(pos - 1, 1, flag || i < mx);
}else{
ans += dp(pos - 1, 0, flag || i < mx);
}
}
if (flag) f[pos][st] = ans;
return ans;
}
int cal(int x){
memset(f, -1, sizeof f);
int xx = x;
int pos = 0;
while(xx){
a[++pos] = xx % 10;
xx /= 10;
}
return dp(pos, 0, 0);
}
signed main(){
int n, m;
while(cin >> n >> m && (n || m)){
cout << cal(m) - cal(n - 1) << '\n';
}
}