BZOJ 4521 [CQOI2016]手机号码 - 数位DP
Description
在$[L, R]$找出有几个数满足两个条件 :
1 : 不同时含有$4$ 和 $8$
2 : 至少有$3$个相邻的数相同
Solution
非常容易的数位DP,
$pos$ 为当前第几位, $ex$ 表示是否出现过$4$ 或 $8$, $pre$表示 前面的是几, $num$表示有几个相邻的数相同。
答案就是 $sum[pos][ex][pre][num] $了QuQ。 $DP$ 和 模板一样。
还需要注意如果$L = 1e10$ , 查$L - 1$ 时必须返回$0$
Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #define ll long long 6 using namespace std; 7 8 int a[15]; 9 ll sum[15][3][15][6]; 10 11 ll dfs(int pos, int ex, int pre, int num, bool lim, bool lead) { 12 if(!pos) 13 return num >= 3; 14 if(!lim && !lead && sum[pos][ex][pre][num] != -1) 15 return sum[pos][ex][pre][num]; 16 int up = lim ? a[pos] : 9; 17 ll tmp = 0; 18 for(int i = 0 ; i <= up; ++i) { 19 if(lead && i == 0) continue; 20 if(ex == 1 && i == 8) continue; 21 if(ex == 2 && i == 4) continue; 22 int nx; 23 if(i == 4) nx = 1; 24 else if(i == 8) nx = 2; 25 else nx = ex; 26 if(pre == i && num < 3) 27 tmp += dfs(pos - 1, nx, i, num + 1, lim && a[pos] == i, false); 28 else if(num >= 3) 29 tmp += dfs(pos - 1, nx, pre, num, lim && a[pos] == i, false); 30 else tmp += dfs(pos - 1, nx, i, 1, lim && a[pos] == i, false); 31 } 32 if(!lim && !lead) sum[pos][ex][pre][num] = tmp; 33 return tmp; 34 } 35 36 ll work(ll x) { 37 if(x < (ll)1e10) 38 return 0; 39 int len = 0; 40 while(x) { 41 a[++len] = x % 10; 42 x /= 10; 43 } 44 return dfs(11, 0, 0, 0, true, true); 45 } 46 47 int main() 48 { 49 ll l, r; 50 scanf("%lld%lld", &l, &r); 51 memset(sum, -1, sizeof(sum)); 52 printf("%lld\n", work(r) - work(l - 1)); 53 }