Codeforces1156E. Special Segments of Permutation

Description

You are given a permutation p of n integers 1, 2, ..., n (a permutation is an array where each element from 1 to n occurs exactly once).
Let's call some subsegment p[l,r] of this permutation special if (p_l + p_r = max limits_{i = l}^{r} p_i). Please calculate the number of special subsegments.

Input

The first line contains one integer n ((3 le n le 2 cdot 10^5)).
The second line contains n integers p1, p2, ..., pn (1≤pi≤n). All these integers are pairwise distinct.

Output

Print the number of special subsegments of the given permutation.

Solution

题目大意就是求区间[l,r]的个数,使得p[l]+p[r]=max(p[x])(x∈[l,r])
考虑枚举这个max
但暴力去做是(O(n^{2}))的,无法接受
先预处理每个数的位置(因为每个数是唯一的,所以可以乱搞)
然后我们暴力做出对于每个点可以向左(向右)能扩展到的位置
最后暴力枚举较短的那段,可以因为预处理了位置,所以可以O(1)判断该点对于当前的max是否合法
平均下来应该是O(n)的吧(雾大雾)

Code

#include <cstdio>
#include <algorithm>
#define N 200001
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
int n,i,tot,ans,a[N],bz[N],l[N],r[N],dui[N];
void pd(int x,int y)
{
    for (int i=x,pl;i<y;i++)
    {
        pl=bz[a[y]-a[i]];
        if (pl>y && pl<=r[y]) ans++;
    }
}
void ps(int x,int y)
{
    for (int i=y,pl;i>x;i--)
    {
        pl=bz[a[x]-a[i]];
        if (pl<x && pl>=l[x]) ans++;
    }
}
int main()
{
    open("Special");
    scanf("%d",&n);
    for (i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        bz[a[i]]=i;
    }
    for (i=1;i<=n;i++)
    {
        while (a[dui[tot]]<a[i] && tot) tot--;
        l[i]=dui[tot]+1;
        dui[++tot]=i;
    }
    tot=0;dui[0]=n+1;
    for (i=n;i>=1;i--)
    {
        while (a[dui[tot]]<a[i] && tot) tot--;
        r[i]=dui[tot]-1;
        dui[++tot]=i;
    }
    for (i=1;i<=n;i++)
        if (i-l[i]<r[i]-i) pd(l[i],i);else ps(i,r[i]);
    printf("%d",ans);
    return 0;
}
如果自己说什麽都做不到而什麽都不去做的话,那就更是什麽都做不到,什麽都不会改变,什麽都不会结束.
原文地址:https://www.cnblogs.com/Sport-river/p/13861233.html