BZOJ 4521 [CQOI2016]*

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

 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
", work(r) - work(l - 1));
53 }
View Code
原文地址:https://www.cnblogs.com/cychester/p/9645535.html