CF1611F 题解

题目描述

给你一个长度为 \(n(n\leq 2e5)\) 的序列 \(a\) 和一个整数 \(s\),求一段最长的连续子序列 \([l,r]\) 使得 \(\forall i\in[l,r],x+\sum\limits_{j=l}^i a_j\geq 0\)

分析

我们首先看到题目给定的这一个限制条件,可以用前缀和来进行一次转化 \(\forall i\in[l,r],x+qzh_i-qzh_{l-1}\geq 0\),再次观察可以发现只要 \([l,r]\) 中最小的 \(qzh_i\) 满足这一个条件,整个区间就可以满足了,求区间最小可以用ST表来做,时间复杂度为查询 \(O(1)\),预处理 \(O(n\log n)\)

然后考虑枚举左端点,在应用二分的方法来寻找右端点,判断用ST表优化到 \(O(1)\),每一组数据时间复杂度 \(O(n\log n)\)

代码实现就不是很复杂了(记得开long long

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int T,n,s;
int qzh[N],a[N];
int f[N][32];
int lg[N];
void Pre(){
    // int xx=loog(n);
    lg[1]=0;
    for(int i=2;i<=n;i++)lg[i]=lg[i/2]+1;
    for(int j=1;j<=lg[n];j++) {
        for(int i=1;i+(1<<j)-1<=n;i++)
            f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
    }
}

int Query(int l,int r){
    int delta=lg[r-l+1];
    return min(f[l][delta],f[r-(1<<delta)+1][delta]);
}
signed main(){
    ios::sync_with_stdio(false);
    cin>>T;
    while(T--){
        cin>>n>>s;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            qzh[i]=qzh[i-1]+a[i];
            for(int j=1;j<=30;j++) f[i][j]=0x3f3f3f3f;
            f[i][0]=qzh[i];
        }
        Pre();
        int ans=-1,ansv=0,ansl=0,ansr=0;
        for(int l=1;l<=n;l++){
            int rl=l,rr=n,fl=0;
            while(rl<=rr){
                int mid=rl+rr>>1;
                if(s+Query(l,mid)-qzh[l-1]<0) rr=mid-1;
                else rl=mid+1,fl=mid;
                // cout<<rl<<' '<<rr<<endl;
            }
            // if(fl==0) continue;
            if(fl-l+1>ansv){
                ansl=l;ansr=fl;
                ansv=fl-l+1;
            }
        }
        if(ansv) cout<<ansl<<' '<<ansr<<endl;
        else cout<<-1<<endl;
    }
    return 0;
}
posted @ 2021-11-26 22:01  Gloamin  阅读(42)  评论(0)    收藏  举报