• 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
    ",ans);
        return 0;
    }
  • 相关阅读:
    SSL 1010——方格取数
    SSL 1558——科技庄园
    SSL 2295——暗黑破坏神
    SSL 2294——打包
    SSL 2293——暗黑游戏
    SSL 2305——竞赛总分
    SSL 1072——砝码称重
    SSL 2291——分组背包
    SSL 2290——潜水员
    SSL 2301——混合背包
  • 原文地址:https://www.cnblogs.com/ChrisKKK/p/11521144.html
Copyright © 2020-2023  润新知