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;
}

浙公网安备 33010602011771号