educational codeforces round 64 (rated for div.2)

链接:https://codeforces.com/contest/1156/problem/E
思路:用单调栈求出一个数左右第一个比他大的数,然后需要证明一个结论,如果我们每次枚举左右中小的那个区间,那么每个数枚举次数不会超过logn次,因为每次都枚举的小的一边,所以每次都至少要除以2,最后不会超过logn次,然后暴力枚举答案即可。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

using namespace std;

int n;
const int maxn = 2e5 + 5;
int a[maxn], pos[maxn];
int l[maxn], r[maxn];
typedef long long ll;
ll res;
stack<int> s;

void (int x, int l, int r, bool f){
if(!f){
for(int i = l; i < x; i++){
if(pos[a[x] - a[i]] > x && pos[a[x] - a[i]] <= r) res++;
}
}
else{
for(int i = x + 1; i <= r; i++){
if(pos[a[x] - a[i]] < x && pos[a[x] - a[i]] >= l) res++;
}
}
}

int main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i], pos[a[i]] = i;
for(int i = 1; i <= n; i++){
while(!s.empty() && a[s.top()] < a[i]){
r[s.top()] = i;
s.pop();
}
s.emplace(i);
}
while(!s.empty()){
r[s.top()] = n + 1;
s.pop();
}

for(int i = n; i; i--){
while(!s.empty() && a[s.top()] < a[i]){
l[s.top()] = i;
s.pop();
}
s.emplace(i);
}
while(!s.empty()){
l[s.top()] = 0;
s.pop();
}


for(int i = 1; i <= n; i++){
int le = l[i] + 1;
int ri = r[i] - 1;
if(i - le < ri - i) update(i, le, ri, 0);
else update(i, le, ri, 1);
}
cout << res << 'n';
return 0;
}