cf1156E. Special Segments of Permutation

链接

https://codeforces.com/problemset/problem/1156/E

题解

这题想到了就没啥难的了
我显然可以枚举最大的那个数是谁,然后确定出在哪个范围内它是最大的(求出左右第一个比他大的分别在哪,基础单调栈)
假设我求出来之后是 [ l i , r i ] [l_i,r_i] [li,ri]
现在问题就是我怎么枚举,肯定左端就在 [ l i , i ) [l_i,i) [li,i),右端点就在 ( i , r i ] (i,r_i] (i,ri]
考虑我如果选择较短的那段,那么最差的情况就是 r i − l i + 1 2 \frac{r_i-l_i+1}{2} 2rili+1这么多循环次数
再想一想,一种极端情况就是序列递增,那么我如果从大到小依次的话,虽然每次区间都很长,但是由于我取较短的那段,每次都是 O ( 0 ) O(0) O(0)的,因此没问题
如果序列长得线段树那样,每次切一半,那我依然可以做到 O ( n l o g n ) O(nlogn) O(nlogn),这其实就似乎最差情况了,想一下,如果稍微不平衡一点,那么根据我取最小的策略,我每次枚举的次数就会减少一些
所以这样做复杂度是比较优秀的

代码

#include <bits/stdc++.h>
#define maxn 200010
#define linf (1ll<<60)
using namespace std;
typedef long long ll;
ll a[maxn], N, l[maxn], r[maxn], f[maxn];
stack<ll> stk;
ll read(ll x=0)
{
    ll c, f=1;
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-48;
    return f*x;
}
int main()
{
    ll N=read(), i, ans(0), j;
    a[0]=a[N+1]=linf;
    for(i=1;i<=N;i++)a[i]=read(), f[a[i]]=i;
    stk.emplace(0);
    for(i=1;i<=N;i++)
    {
        while(a[stk.top()]<a[i])stk.pop();
        l[i]=stk.top()+1;
        stk.emplace(i);
    }
    while(!stk.empty())stk.pop();
    stk.emplace(N+1);
    for(i=N;i;i--)
    {
        while(a[stk.top()]<a[i])stk.pop();
        r[i]=stk.top()-1;
        stk.emplace(i);
    }
    for(i=1;i<=N;i++)
    {
        if(i-l[i] < r[i]-i)
        {
            for(j=l[i];j<i;j++)
            {
                if(i<f[a[i]-a[j]] and f[a[i]-a[j]]<=r[i])ans++;
            }
        }
        else
        {
            for(j=i+1;j<=r[i];j++)
            {
                if(l[i]<=f[a[i]-a[j]] and f[a[i]-a[j]]<i)ans++;
            }
        }
    }
    printf("%lld",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值