CF1156E Special Segments of Permutation【题解】瞎搞 单调栈

题面:http://codeforces.com/contest/1156/problem/E

Luogu翻译:https://www.luogu.com.cn/problem/CF1156E

话说Luogu要改域名了

大意:给定一个长度为n的排列p,求有多少区间[l,r]满足,p[l]+p[r]=max{p[i]},其中l<=i<=r

据说可以笛卡尔树。

可是我不会

那么就瞎搞。

预处理出左边第一个比a[i]大的数的位置,记为L[i]

R[i]同理为右边。

这个可以用单调栈求。

然后就可以枚举l和r了。

但是显然这样会爆炸。

但是由于题目的限制,可以只枚举一边。

另外一边直接查询有没有。

比如枚举了l,那么p[r]=pmax-p[l]

只用知道右边有没有p[r]就可以了。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn=2*1e5+10;
int n,a[maxn],pos[maxn];
long long ans;
int L[maxn],R[maxn],s[maxn];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        pos[a[i]]=i;
    }
    int top=0;
    for(int i=1;i<=n;i++){
        while(top && a[s[top]]<a[i]) top--;
        L[i]=s[top];
        s[++top]=i;
    }
    top=0;s[top]=n+1;
    for(int i=n;i;i--){
        while(top && a[s[top]]<a[i]) top--;
        R[i]=s[top];
        s[++top]=i;
    }
    for(int i=1;i<=n;i++){
        if(i-L[i]<R[i]-i){
            for(int j=L[i]+1;j<i;j++)
                if(pos[a[i]-a[j]]>i && pos[a[i]-a[j]]<R[i]) ans++;
        }else{
            for(int j=i+1;j<R[i];j++)
                if(pos[a[i]-a[j]]<i && pos[a[i]-a[j]]>L[i]) ans++;
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ChrisKKK/p/11521144.html
今日推荐