Codeforces 1156E Special Segments of Permutation
题目链接
https://codeforces.com/contest/1156/problem/E
题目大意
给你一个长度为 $n$ 的排列 $p$ ,问满足 $p_l + p_r = \max \limits_{i = l}^{r} p_i$ 的连续子序列 $p[l, r]$ 有多少种。
题目分析
考虑使用分治来解决本题。对于一个区间,左右区间内对答案的贡献计算出来之后,考虑如何解决跨区间的问题。由于询问的一直是左右端点和最大值的关系,因此可以采用两个指针在左侧和右侧扫描,如果比最大值小那么就可以扩展区间,扩展的同时记录是否可以构造出最大值,如果两个指针所指向的全部都大于当前最大值,选择更小的那个数拓展区间即可。这样显然每个最大值所能影响到的几个端点都能覆盖到,因此最终可以求得总和。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <algorithm> using namespace std; const int maxn = 2e5 + 5; int n, m, t; int a[maxn]; int visl[maxn]; int visr[maxn]; long long ans = 0; int read(){ int x; scanf("%d", &x); return x; } int dfs(int l, int r){ int x, y; int mid = (l + r) / 2; int maxx = 0; if(l == r)return 0; dfs(l, mid); dfs(mid + 1, r); x = mid, y = mid + 1; maxx = max(a[x], a[y]); visl[a[x]] = 1; visr[a[y]] = 1; while(true){ while(x - 1 >= l and a[x - 1] <= maxx){ x--; visl[a[x]]++; ans += visr[maxx - a[x]]; } while(y + 1 <= r and a[y + 1] <= maxx){ y++; visr[a[y]]++; ans += visl[maxx - a[y]]; } if(l == x and y == r)break; if(x - 1 < l){ y++; visr[a[y]]++; maxx = max(maxx, a[y]); }else if(y + 1 > r){ x--; visl[a[x]]++; maxx = max(maxx, a[x]); }else if(a[x - 1] > a[y + 1]){ y++; visr[a[y]]++; maxx = max(maxx, a[y]); }else if(a[x - 1] < a[y + 1]){ x--; visl[a[x]]++; maxx = max(maxx, a[x]); }else{ y++; visr[a[y]]++; maxx = max(maxx, a[y]); x--; visl[a[x]]++; maxx = max(maxx, a[x]); } } for(int i=l;i<=r;i++){ visl[a[i]] = 0; visr[a[i]] = 0; } return 0; } int main(){ int i, j; n = read(); for(i=1;i<=n;i++){ a[i] = read(); } dfs(1, n); printf("%lld\n", ans); return 0; }