[2019杭电多校第十场][hdu6701]Make Rounddog Happy

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6701

题目大意为求满足 $max(a_{l},a_{l+1}\cdot \cdot \cdot a_{r})-(r-l+1)<=k$的区间个数。

先预处理出前缀最大值和后缀最大值和ST表,然后分治。

每次可以得到这次分治区间的区间最大值,然后我们要求出以该最大值为区间最大值时的合法区间数目。

这里我们可以枚举合法区间的左端点(右端点),然后通过化简上式得到合法的右端点(左端点),选择枚举左还是右端点由当前区间最大值的位置所决定,因为左端点一定在最大值左边,右端点一定在最大值右边,所以选择数量较小的一边来枚举。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<set>
 6 using namespace std;
 7 typedef long long ll;
 8 typedef unsigned long long ull;
 9 const int maxn = 3e5 + 110;
10 int a[maxn], pos[maxn], L[maxn], R[maxn], Log[maxn];
11 int n, k;
12 int dp[maxn][20];
13 int query(int l, int r) {
14     int k = Log[r - l + 1];
15     if (a[dp[l][k]] > a[dp[r - (1 << k) + 1][k]])
16         return dp[l][k];
17     else
18         return dp[r - (1 << k) + 1][k];
19 }
20 ll dfs(int l, int r) {
21     if (l == r)return a[l] - 1 <= k;
22     if (l > r)return 0;
23     int cnt = query(l, r);
24     ll ans = 0;
25     if (cnt - l < r - cnt) {
26         for (int i = l; i <= cnt; i++) {
27             int ls = max(cnt, i + a[cnt] - k - 1);
28             int rs = min(r, R[i]);
29             if (rs >= ls)
30                 ans += rs - ls + 1;
31         }
32     }
33     else {
34         for (int i = cnt; i <= r; i++) {
35             int ls = max(l, L[i]);
36             int rs = min(i - (a[cnt] - k) + 1, cnt);
37             if (rs >= ls) ans += rs - ls + 1;
38         }
39     }
40     return ans + dfs(l, cnt - 1) + dfs(cnt + 1, r);
41 }
42 int main() {
43     int t;
44     scanf("%d", &t);
45     while (t--) {
46         scanf("%d%d", &n, &k);
47         for (int i = 1; i <= n; i++)
48             scanf("%d", &a[i]);
49         Log[0] = -1;
50         for (int i = 1; i <= n; i++) Log[i] = Log[i >> 1] + 1;
51         for (int i = 1; i <= n; i++)
52             dp[i][0] = i;
53         for (int j = 1; (1 << j) <= n; j++) {
54             for (int i = 1; i + (1 << j) - 1 <= n; i++) {
55                 if (a[dp[i][j - 1]] > a[dp[i + (1 << (j - 1))][j - 1]])
56                     dp[i][j] = dp[i][j - 1];
57                 else
58                     dp[i][j] = dp[i + (1 << (j - 1))][j - 1];
59             }
60         }
61         for (int i = 0; i <= n; i++)pos[i] = 0;
62         R[n + 1] = n;
63         for (int i = n; i >= 1; i--) {
64             if (pos[a[i]]) {
65                 R[i] = pos[a[i]] - 1;
66                 pos[a[i]] = i;
67             }
68             else {
69                 pos[a[i]] = i;
70                 R[i] = n;
71             }
72             R[i] = min(R[i], R[i + 1]);
73         }
74         for (int i = 0; i <= n; i++)pos[i] = 0;
75         for (int i = 1; i <= n; i++) {
76             if (pos[a[i]]) {
77                 L[i] = pos[a[i]] + 1;
78                 pos[a[i]] = i;
79             }
80             else {
81                 pos[a[i]] = i;
82                 L[i] = 1;
83             }
84             L[i] = max(L[i], L[i - 1]);
85         }
86         printf("%lld\n", dfs(1, n));
87     }
88 }

 

posted @ 2019-08-26 19:23  祈梦生  阅读(213)  评论(0编辑  收藏  举报