做法是,先求出前缀和pre。然后枚举端点i,[i+1,n]中pre最小的找出来,减去pre[i-1]大于0,这是第一个条件;第二个条件是,从i开始的后缀和和i之前的最小的一个pre相加大于0。只要满足这两个条件那么这个端点就是可行的。显然找这两个区间的最值都是可以用数组线性维护的,因此总体复杂度是O(n)的。
代码如下:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <algorithm> 4 using namespace std; 5 const int N = 2e5 + 5; 6 7 int a[N]; 8 int pre[N],suf[N]; 9 int min_pre_qian[N],min_pre_hou[N]; 10 11 int main() 12 { 13 int T; 14 scanf("%d",&T); 15 while(T--) 16 { 17 int n; 18 scanf("%d",&n); 19 for(int i=1;i<=n;i++) 20 { 21 scanf("%d",a+i),pre[i] = pre[i-1] + a[i]; 22 if(i == 1) min_pre_qian[i] = pre[1]; 23 else min_pre_qian[i] = min(pre[i], min_pre_qian[i-1]); 24 } 25 suf[n+1] = 0; 26 for(int i=n;i>=1;i--) 27 { 28 suf[i] = suf[i+1] + a[i]; 29 if(i == n) min_pre_hou[i] = pre[i]; 30 else min_pre_hou[i] = min(min_pre_hou[i+1], pre[i]); 31 //min_suf[i] = min(suf[i], min_suf[i+1]); 32 } 33 int ans = 0; 34 for(int i=1;i<=n;i++) 35 { 36 //printf("%d %d %d %d %d ?? ",i,min_pre_hou[i],pre[i-1],suf[i],max_pre_qian[i-1]); 37 if(min_pre_hou[i] - pre[i-1] > 0 && suf[i] + min_pre_qian[i-1] > 0) 38 { 39 ans++; 40 } 41 } 42 printf("%d ",ans); 43 } 44 }