1. 程式人生 > >The Preliminary Contest for ICPC China Nanchang National Invitational I.Max answer單調棧

The Preliminary Contest for ICPC China Nanchang National Invitational I.Max answer單調棧

anti 有變 定義 else ont def 所有 註意 復雜

題面

題意:一個5e5的數組,定義一個區間的值為 這個區間的和*這個區間的最小值,註意數組值有負數有正數,求所有區間中最大的值

題解:如果全是正數,那就是原題 POJ2796 單調棧做一下就ok

我們現在有負數,考慮這段區間,他的和必須是負數,由於導致和為負數,最小值一定也是負數,

那對於這樣一個和為負的區間進行擴展的時候,遇見下一個數,是負數,我們一定會擴展,無論這個負數大小

遇見下一個是正數,如果和沒有變正,那就可以繼續擴展下去(不更新答案罷了)

所以我們對於那些和為負的區間,單獨統計一下答案就好了,順路就統計這個區間的最小值,因為一旦拋棄她就再也不會回頭了!

所以壓根不用線段樹 ST表之類的,對於負數的和,整體按POJ2796做的取個min,就行了.復雜度O(n)

 1 #include<bits/stdc++.h>
 2 #define lld long long 
 3 #define N 500050
 4 using namespace std;
 5 int n;
 6 lld a[N],sum[N],x[N],xx[N];
 7 lld L[N],R[N],ansv,ans1;
 8 int main ()
 9 {
10     scanf("%d", &n);
11
for (int i=1;i<=n;i++) 12 { 13 scanf("%lld",&x[i]); 14 xx[i]=x[i]; 15 } 16 lld ww=xx[1],minx=xx[1]; 17 for (int i=1;i<=n;i++) 18 { 19 if (xx[i-1]<0) 20 { 21 minx=min(minx,xx[i]); 22 xx[i]+=xx[i-1
]; 23 }else 24 { 25 xx[i]+=0; 26 minx=1e18; 27 } 28 if (xx[i]<ww) 29 { 30 ww=xx[i]; 31 ansv=minx; 32 } 33 } 34 if (ww<0) ans1=ww*ansv; 35 for (int i=1;i<=n;i++) a[i]=x[i]; 36 for (int i=1;i<=n;i++) 37 { 38 sum[i]=sum[i-1]+a[i]; 39 L[i]=R[i]=i; 40 } 41 a[0]=a[n+1]=-1e9; 42 for (int i=1;i<=n;i++) 43 while(a[i]<=a[L[i]-1]) L[i]=L[L[i]-1]; 44 for (int i=n;i>=1;i--) 45 while(a[i]<=a[R[i]+1]) R[i]=R[R[i]+1]; 46 lld ans=-1e18,l,r; 47 for (int i=1;i<=n;i++) 48 { 49 lld T=a[i]*(sum[R[i]]-sum[L[i]-1]); 50 if(ans<T) ans=T,l=L[i],r=R[i]; 51 } 52 cout<<max(ans,ans1)<<endl; 53 }

The Preliminary Contest for ICPC China Nanchang National Invitational I.Max answer單調棧