"###Feel Good"
阿新 • • 發佈:2018-12-17
題面描述
問題描述
給出一個長度為n(1<=n<=100 000)的序列,求出一個子序列,使得這個序列中的最小值乘以這個序列的和的值最大。
輸入格式
輸入資料有2行,第一行正整數n,第2行n個正整數ai。(0<=ai<=10^6)
輸出格式
輸出有2行,第一行為題目描述中的最大值,第二行2個數字,分別為子序列的起點和終點位置,如果有多個子序列相等,那麼選擇起點靠前的。
樣例輸入
6
3 1 6 4 5 2
樣例輸出
60
3 5
限制與約定
時間限制:1s
空間限制:128MB
題解
我們開兩個單調棧l[i]和r[i],從1~n 列舉 每個數,對於數 i,l[i]存 i點左邊第一個比a[i]小的數的編號,r[i]存 i點右邊第一個比a[i]小的數的編號,顯然,l[i] 到 r[i] 這個子序列的最小值為a[i] 。因為序列為正整數序列,所以a[i] 為最小值的子序列能取到的最大值k為 l[i]~r[i] 的和乘上a[i] ,l[i]~r[i] 的和用字首和處理出來,不斷用k更新ans*(注意:ans要開 long long 型別)*,詳見程式碼
程式碼實現
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdlib> using namespace std; long long a[100005],sum[100005]; int n,ll,rr,l[100005],r[100005]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i];//字首和處理 l[i]=r[i]=i; } for(int i=2;i<=n;i++) while(l[i]>1 && a[l[i]-1]>=a[i]) l[i]=l[l[i]-1]; for(int i=n-1;i>=1;i--) while(r[i]<n && a[r[i]+1]>=a[i]) r[i]=r[r[i]+1]; //單調棧處理 long long ans=-1; for(int i=1;i<=n;i++) { long long k=a[i]*(sum[r[i]]-sum[l[i]-1]); if(k>ans)//若k>ans 更新答案,注意:k==ans 時不要更新答案 { ans=k; ll=l[i]; rr=r[i]; } } printf("%lld\n%d %d",ans,ll,rr); return 0; }
若您覺得此篇部落格寫得不錯,請別忘了關注我哦 >_<