Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 10430 | Accepted: 2855 | |
Case Time Limit: 1000MS | Special Judge |
Description
Input
Output
Sample Input
6 3 1 6 4 5 2
Sample Output
60 3 5
Source
计算区间的最大值,某个区间的值等于 (区间的最小值)*(区间所有值之和),求出所有这样的值中的最大值。
基本思路就是从1到n每次枚举第i个值作为最小值,从i往左边找到尽可能小的下标l,满足[l,i]区间的值>=a[i],同理往右边找出尽可能大的下标r,满足[i,r]>=a[i],也就是找到以a[i]为最小值区间的起点和终点,该区间计算出来的最大值就是a[i]*区间和。显然需要预处理前缀和。
对于l,r,直接查找的话是o(n^2),但是区间最小值的满足单调性的,因为一定满足min[l,r] >= min[l,r+1],也满足min[l-1,r] <= min[l,r],所以可以用st算法预处理区间最小值,每次枚举后利用二分查找,找出符合条件的最大区间,O(nlogn)。
用st算法必须预处理出所有的log(i),不然会慢很多图
#include
#include
#include
#include
using namespace std;
#define maxn 100001
#define ll long long
int n;
int stmin[maxn][20];
ll pre[maxn];
double ln[maxn];
void init_st()
{
for(int i = 1; i <= n; i++)
scanf("%d", &stmin[i][0]);
for(int j = 1; (1< r) return -1;
int p = ln[r-l+1];
return min(stmin[l][p], stmin[r-(1<= mini){
tmp = mid;
ub = mid;
}
else
lb = mid+1;
}
ll val = (pre[i]-pre[tmp-1])*mini;
int tmp1 = i;
lb = i, ub = n+1;
while(lb < ub){
mid = lb+(ub-lb)/2;
if(get_min(i, mid) >= mini){
tmp1 = mid;
lb = mid+1;
}
else
ub = mid;
}
val += (pre[tmp1]-pre[i])*mini;
// cout < ans){
ans = val;
l = tmp;
r = tmp1;
}
}
printf("%I64d\n%d %d\n", ans , l, r);
}
return 0;
}
还有一种做法是利用单调栈,O(n)求出每个点i的左边界和右边界. 总体复杂度O(n)
#include
#include
#include
#include
using namespace std;
#define maxn 100001
typedef long long ll;
int a[maxn];
ll pre[maxn];
int l[maxn], r[maxn];
int n;
int main()
{
while(~scanf("%d", &n)){
pre[0] = 0;
for(int i = 0; i < n; i++){
scanf("%d", a+i);
pre[i+1] = pre[i]+a[i];
}
stack s;
for(int i = 0; i < n; i++){
while(!s.empty() && a[s.top()] >= a[i]) s.pop();
l[i] = s.empty() ? 0 : s.top()+1;
s.push(i);
}
while(!s.empty()) s.pop();
for(int i = n-1; i >= 0; i--){
while(!s.empty() && a[s.top()] >= a[i]) s.pop();
r[i] = s.empty() ? n-1 : s.top()-1;
s.push(i);
}
ll ans = -1, tmp;
int ll, rr;
for(int i = 0; i < n; i++){
tmp = a[i]*(pre[r[i]+1]-pre[l[i]]);
if(tmp > ans) ans = tmp, ll = l[i]+1, rr = r[i]+1;
}
printf("%I64d\n%d %d\n", ans, ll, rr);
}
return 0;
}