链接:https://ac.nowcoder.com/acm/problem/19945
来源:牛客网

题目描述

人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号 码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数 量。
工具需要检测的号码特征有两个:号码中要出现至少3个相邻的相同数字,号码中不能同时出现8和4。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、 23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。 手机号码一定是11位数,前不含前导的0。工具接收两个数L和R,自动统计出[L,R]区间 内所有满足条件的号码数量。L和R也是11位的手机号码。

输入描述:

输入文件内容只有一行,为空格分隔的2个正整数L,R。
10^10 ≤ L ≤ R < 10^11

输出描述:

输出文件内容只有一行,为1个整数,表示满足条件的手机号数量。
示例1

输入

12121284000 12121285550

输出

5

说明

样例解释
满足条件的号码: 12121285000、 12121285111、 12121285222、 12121285333、 12121285550
 

析:很容易可以看出来是一个数位DP,dp[pos][last][sum][num][enough]表示前 pos 位,上一位是last,已经出现了sum次,num是一个二进制位的表示是否出现过4或者8,enough表示是否已经连续出现过三个相同的数字,然后就很简单了。

代码如下:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#include <sstream>
#include <list>
#include <assert.h>
#include <bitset>
#include <numeric>
#define debug() puts("++++")
#define gcd(a, b) __gcd(a, b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a, b, sizeof a)
#define sz size()
#define be begin()
#define ed end()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
#define all 1,n,1
#define FOR(i,n,x)  for(int i = (x); i < (n); ++i)
#define freopenr freopen("in.in", "r", stdin)
#define freopenw freopen("out.out", "w", stdout)
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e17;
const double inf = 1e20;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 5e5 + 7;
const int maxm = 2000000 + 7;
const LL mod = 1e9 + 9;
const int dr[] = {-1, 1, 0, 0, 1, 1, -1, -1};
const int dc[] = {0, 0, 1, -1, 1, -1, 1, -1};
int n, m;
inline bool is_in(int r, int c) {
  return r >= 0 && r < n && c >= 0 && c < m;
}


LL dp[15][10][15][4][2];
int a[15];
int is_first;

LL dfs(int pos, int last, int sum, int num, bool enough, bool ok){
  if(!pos)  return num != 3 && enough;
  LL &ans = dp[pos][last][sum][num][enough];
  if(!ok && ans != -1)  return ans;
  int start = is_first;  is_first = 0;
  int n = ok ? a[pos] : 9;
  LL res = 0;
  for(int i = start; i <= n; ++i){
    if(i == 4 && !(num&2))  res += dfs(pos-1, i, last == i ? sum+1 : 1, num|1, enough || (last==i && sum >= 2), ok && i == n);
    else if(i == 8 && !(num&1))  res += dfs(pos-1, i, last == i ? sum+1 : 1, num|2, enough || (last==i && sum >= 2), ok && i == n);
    else if(!i || i % 4)  res += dfs(pos-1, i, last == i ? sum+1 : 1, num, enough || (last==i && sum >= 2), ok && i == n);
  }
  if(!ok)  ans = res;
  return res;

}

LL solve(LL n){
  if(n < 10000000000LL)  return 0LL;
  int len = 0;
  while(n){
    a[++len] = n % 10;
    n /= 10;
  }
  is_first = 1;
  return dfs(len, 0, 0, 0, 0, true);
}

int main(){
  ms(dp, -1);
  LL n, m;
  cin >> m >> n;
  cout << solve(n) - solve(m-1) << endl;
  return 0;
}