思路:
直接二分长度不可行,因为有负数。
考虑枚举坐便删l个数,那如果可以在短时间内求出符合条件的右边最小删的数的个数,这题便可做了。
即:当左边删l个数时,要使sum[n]-sum[l]-fsum[n+1-x] <= s成立,求出最小的x。(sum为前缀和,fsum为后缀和)
思考后可以发现可行的fsum[x]必然要是正数,可能的答案x必然是单调递增的(x从0开始)。
所以维护一个大于0的递增的单调栈即可,在里面二分找答案。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define MP make_pair 6 #define PB push_back 7 typedef long long LL; 8 typedef pair<int,int> PII; 9 const double eps=1e-8; 10 const double pi=acos(-1.0); 11 const int K=1e6+7; 12 const LL mod=1e9; 13 14 int n,cnt,tot,ans=K,nl,id[K]; 15 LL s,tmp,sum[K],q[K]; 16 17 void check(int x) 18 { 19 int ta=lower_bound(q,q+tot+1,sum[n]-sum[x]-s)-q; 20 if(sum[n]-sum[x]-q[ta]<=s && x+n-id[ta]+1 < ans) 21 ans=x+n-id[ta]+1,nl=x; 22 } 23 int main(void) 24 { 25 cin>>n>>s; 26 id[0]=n+1; 27 for(int i=1,x;i<=n;i++) scanf("%d",&x),sum[i]+=sum[i-1]+x; 28 for(int i=n;i;i--) 29 { 30 tmp+=sum[i]-sum[i-1]; 31 if(tmp>q[tot]) 32 q[++tot]=tmp,id[tot]=i; 33 } 34 for(int i=0;i<=n;i++) 35 { 36 if(id[tot]==i) tot--; 37 check(i); 38 } 39 if(ans>=n) 40 printf("-1\n"); 41 else 42 printf("%d\n%d %d\n",n-ans,nl,ans-nl); 43 return 0; 44 }
时间: 2024-10-11 15:42:58