大体题意:
给你一个长度为n (n <= 100000)的正整数序列ai,求出一段连续子序列a1,,ar 使得 (a1 + a2+ a3 +... ar) * min (a1,a2,a3,,,,ar)尽量大 如果多解任意输出一个!
思路:
思路是比较清晰的,就是有坑:
用sum[i]表示 1 ...i 的和,l[i],r[i],分别表示以第 i 个数字为最小值所能扩展的最左端和最右端!
最后遍历i 更新ans
ll ans = a[i] * (sum[r[i]] - sum[l[i]-1]);
取个最大值即可!
求l 和r 数组还不能暴力求,这样会超时。
for (int i = 1; i <= n; ++i)
while(a[l[i]-1] >= a[i])l[i] = l[l[i]-1];
这样求得话 因为遍历到i 时,l[i] 肯定等于i 的,所以当i的位置前一个数值大于等于 第i 个数值时,第i个数值就应该扩展到 第i个数 前一个位置的数 所能扩展到的位置!
r数组 同理。
最后是更新ans
记录下标时 pl 记录l pr 记录r 他们必须初始化,因为刚上来可能是0嘛! 数据问题!
然后MAX 初始化为0 在与ans 不断比较就可以了
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fin freopen("cin.txt","r",stdin);
#define fout freopen("out.txt","w",stdout);
using namespace std;
typedef long long ll;
const int INF = 1e9+5;
const int maxn = 100000 + 10;
int n,a[maxn];
ll sum[maxn];
int pl,pr,cnt;
int l[maxn],r[maxn];
int main(){
// fin;
while(scanf("%d",&n) == 1){
for (int i = 1; i <= n; ++i){
scanf("%d",&a[i]);
sum[i] = sum[i-1] + a[i];
l[i] = r[i] = i;
}
a[0] = -INF;
a[n+1] = -INF;
for (int i = 1; i <= n; ++i)
while(a[l[i]-1] >= a[i])l[i] = l[l[i]-1];
for (int i = n; i >= 1; --i)
while(a[r[i]+1] >= a[i])r[i] = r[r[i]+1];
// printf("start\n");
// for (int i = 1; i <= n; ++i)printf("%d ",a[i]);
// printf("\n");
// for (int i = 1; i <= n; ++i)printf("%d ",l[i]);
// printf("\n=\n");
// for (int i = 1; i <= n; ++i)printf("%d ",r[i]);
// printf("\n");
ll MAX = 0;
pl = pr = 1;
for (int i = 1; i <= n; ++i){
ll ans = a[i] * (sum[r[i]] - sum[l[i]-1]);
if (ans > MAX){
// printf("%lld\n",ans);
MAX = ans;
pl = l[i];
pr = r[i];
}
}
if (cnt++)printf("\n");
printf("%lld\n%d %d\n",MAX,pl,pr);
}
return 0;
}