Educational Codeforces Round 64 (Rated for Div. 2)E. Special Segments of Permutation(单调栈+分治)

题目链接:https://codeforces.com/contest/1156/problem/E

题意:给你1 - n的序列并且这n个数只出现一次,定义区间[l, r]中的最大值为x,对于区间[l, r],如果a[l]+a[r]=x,则称这个区间为特殊区间,问你特殊区间有多少个?

思路:用单调栈预处理,对于i位置x从左往右第一个比x大的数的位置l[i],从右往左第一个比x大的数的位置r[i],那么对于区间[l[i]+1,i-1]都是比x小的数,区间[i+1,r[i]-1]也都比x小,也就是说x是区间[l[i],r[i]]的最大值,知道最大值后我们利用分治的思想,遍历小区间,判断x-a[i]是否在大区间即可。

#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;
}

 

你可能感兴趣的:(【单调队列,/,单调栈】)