题目链接:https://codeforces.com/contest/1156/problem/E
题意:给你1 - n的序列并且这n个数只出现一次,定义区间中的最大值为
,对于区间
,如果
,则称这个区间为特殊区间,问你特殊区间有多少个?
思路:用单调栈预处理,对于位置
从左往右第一个比
大的数的位置
,从右往左第一个比
大的数的位置
,那么对于区间
都是比
小的数,区间
也都比
小,也就是说
是区间
的最大值,知道最大值后我们利用分治的思想,遍历小区间,判断
是否在大区间即可。
#include
using namespace std;
const int N = 2e5 + 7;
int l[N], r[N], a[N], id[N], n, ans;
void update(int l, int r, int l2, int r2, int sum)
{
for(int i = l; i <= r; i++)
{
int k = sum - a[i];
if(k >= 1 && k <= n && l2 <= id[k] && id[k] <= r2)
ans++;
}
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
id[a[i]] = i;
}
stack s;
for(int i = 1; i <= n; i++)
{
while(s.size() && a[i] > a[s.top()]) s.pop();
if(!s.size()) l[i] = 0;
else l[i] = s.top();
s.push(i);
}
while(!s.empty())s.pop();
for(int i = n; i >= 1; i--)
{
while(s.size() && a[i] > a[s.top()]) s.pop();
if(!s.size()) r[i] = n + 1;
else r[i] = s.top();
s.push(i);
}
for(int i = 1; i <= n; i++)
{
int l_len = i - l[i] - 1;
int r_len = r[i] - i - 1;
if(l_len == 0 || r_len == 0)
continue;
if(l_len < r_len)
update(l[i] + 1, i - 1, i + 1, r[i] - 1, a[i]);
else
update(i + 1, r[i] - 1, l[i] + 1, i - 1, a[i]);
}
cout << ans << endl;
}