题目
题意:给定1到n的排列,
h
h
h,定义位置
1
<
=
i
<
j
<
=
n
1<=i<j<=n
1<=i<j<=n是可回返的,当且仅当
h
k
<
m
i
n
(
h
i
,
h
j
)
,
i
<
k
<
j
h_k<min(h_i,h_j),i<k<j
hk<min(hi,hj),i<k<j,计算所有这个数中,可回返的点对的距离之和。两个位置
i
,
j
(
i
<
j
)
i,j(i<j)
i,j(i<j)的距离为
j
−
i
+
1
j-i+1
j−i+1
思路:从左到右枚举这n个数,维护单调不增栈,栈存储下标。
1、对于当前的数
h
[
i
]
h[i]
h[i],如果当前栈顶元素对应的值小于它,即
h
[
s
t
.
t
o
p
(
)
]
<
h
[
i
]
h[st.top()]<h[i]
h[st.top()]<h[i],说明该栈顶元素不能和更后边的下标下标组成可回返的点对了(因为被
h
i
h_i
hi挡住了),只能和当前元素组成点对,计算贡献后,弹出该栈顶元素。
2、重复以上过程,直到栈空或者栈顶元素对应的值不小于
h
i
h_i
hi
3、如果最后栈非空,说明栈顶元素对应的值不小于
h
i
h_i
hi,那么它也可以和
h
i
h_i
hi组成点对。
4、将下标
i
i
i加入栈中,枚举下一个数,重复1-4过程。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mx 1e18
const int maxn = 300010;
int n, a[maxn];
int main() {
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
}
stack<int> st;
ll ans = 0;
for (int i = 0; i < n; ++i) {
while (!st.empty() && a[st.top()] < a[i]) {
ans += i - st.top() + 1;
st.pop();
}
if (!st.empty()) {
ans += i - st.top() + 1;
}
st.push(i);
}
printf("%lld\n", ans);
return 0;
}
/*
4 1 2 3 5 6 7
*/