本题很妙,有多种方法求解。我讲常见的4种做法。
我们记录 l e f t [ i ] left[i] left[i], r i g h t [ i ] right[i] right[i]分别表示i这个位置最左和最右能到的位置,则答案为( r i g h t [ i ] right[i] right[i] - l e f t [ i ] left[i] left[i] + 1) * h[i] 的最大值;(注意开long long)
至于求 l e f t [ i ] left[i] left[i] 和 r i g h t [ i ] right[i] right[i]的求法……先看看下面的代码片段。
while(left[i] - 1 >= 1 && h[left[i] - 1] >= h[i]){
left[i] = left[left[i] - 1];
}
这就是 l e f t [ i ] left[i] left[i]的求法, r i g h t [ i ] right[i] right[i]同理。
#include
#include
#include
#include
using namespace std;
const int N = 100005;
long long a[N];
int l[N];
int r[N];
int main(){
int n, i;
while(1){
scanf("%d", &n);
if(n == 0) break;
for(i = 1; i <= n; i++){
scanf("%lld", &a[i]);
l[i] = i;
r[i] = i;
}
for(i = 1; i <= n; i++){
while(l[i] - 1 >= 1 && a[l[i] - 1] >= a[i]){
l[i] = l[l[i] - 1];
}
}
for(i = n; i >= 1; i--){
while(r[i] + 1 <= n && a[r[i] + 1] >= a[i]){
r[i] = r[r[i] + 1];
}
}
long long ans = -1;
for(i = 1; i <= n; i++){
ans = max(ans, (r[i] - l[i] + 1) * a[i]);
}
printf("%lld\n", ans);
}
return 0;
}
在这个单调栈中,维护最小值。每次入栈需要放入一个pair,first 存储值,second存储位置。当一个pair弹出并且枚举到 i 时,说明i的高度比这个大(所以弹出)
这个位置的高度最右能到达i - 1,
最左能到达弹出后栈顶元素的位置加一。
每次更新最大值。记住最后将高度为 0 的加入。弹出剩余的。
#include
#include
#include
#include
#include
using namespace std;
long long Max(long long a,long long b){
return a > b? a : b;
}
int main(){
int n, i, x;
stack<pair<int, int> > st;
pair<int, int> t;
long long ans=-1;
while(1){
scanf("%d", &n);
ans = -1;
if(n == 0)break;
for(i = 1; i <= n + 1; i++){
if(i <= n)
scanf("%d", &x);
else
x = 0;
while(!st.empty() && st.top().first >= x){
t = st.top();
st.pop();
if(st.empty())ans = Max(ans, ((long long)(i - 1)) * (long long)t.first);//注意特判,否则有可能RE
else ans = Max(ans,((long long)(i-1)-(long long)(st.top().second+1)+1LL)*(long long)t.first);
}
if(i <= n)
st.push(make_pair(x, i));
}
printf("%lld\n", ans);
}
return 0;
}
先求出所有位置中高度最低的(用ST表找出),用它的长度 * 总长度来更新答案;
然后以这个点分成2段,递归求解。
#include
#include
#include
#include
using namespace std;
const int N = 100005;
long long a[N];
long long ans;
namespace rmq {
const int MAX_LOG = 23;
int b[MAX_LOG][N];
int Log[N];
void rmq_init(long long a[], int n) {
memset(b, 0, sizeof(b));
Log[1] = 0;
for (int i = 2; i < N; i++) {
Log[i] = Log[i >> 1] + 1;
}
for (int i = 0; i < n; i++) {
b[0][i] = i;
}
for (int i = 1; i < MAX_LOG; i++) {
int limit = n - (1 << i);
for (int j = 0; j <= limit; j++) {
if (a[b[i - 1][j]] < a[b[i - 1][j + (1 << i >> 1)]]) {
b[i][j] = b[i - 1][j];
} else {
b[i][j] = b[i - 1][j + (1 << i >> 1)];
}
}
}
}
long long get_minimum(long long a[], int l, int r) {
int m = Log[r - l + 1];
return min(a[b[m][l]], a[b[m][r - (1 << m) + 1]]);
}
int get_minimum_position(long long a[], int l, int r) {
int m = Log[r - l + 1];
return a[b[m][l]] < a[b[m][r - (1 << m) + 1]] ? b[m][l] : b[m][r - (1 << m) + 1];
}
}
using namespace rmq;
void dfs(int l, int r){
if(l == r){
ans = max(ans, a[l]);
return;
}
int pos = get_minimum_position(a, l, r);
long long t = get_minimum(a, l, r);
ans = max(ans, t * (r - l + 1));
if(pos > l)
dfs(l, pos - 1);
if(pos < r)
dfs(pos + 1, r);
}
int main(){
int n, i;
while(1){
scanf("%d", &n);
if(n == 0)break;
for(i = 0; i < n; i++){
scanf("%d", &a[i]);
}
ans = -1;
rmq_init(a, n);
dfs(0, n - 1);
printf("%lld\n", ans);
}
return 0;
}
根据原数组,借助栈建一棵笛卡尔树,所以,每次只需用 每个子树的大小 * 该子树根结点的点权 来更新答案
#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 100005;
struct note {
int k, a;
int id;
}s[N];
int p[N];
int l[N];
int r[N];
struct node{
node *lc, *rc;
int value, sz;
node(){
lc = rc = NULL;
}
long long dfs();
}*root, *memory, pool[N];
stack<node*> st;
bool cmp(note s1, note s2){
return s1.k < s2.a;
}
void insert(int num){
if(root == NULL){
root = new(memory++) node();
root->value = num;
st.push(root);
}
else{
node *new_node = new(memory++) node();
new_node->value = num;
node *last = NULL;
while(!st.empty() && num < st.top()->value){
last = st.top();
st.pop();
}
if(st.empty()){
new_node->lc = last;
root = new_node;
}
else{
st.top()->rc = new_node;
new_node->lc = last;
}
st.push(new_node);
}
}
long long node::dfs(){
long long lv = -1, rv = -1;
if(lc){
lv = lc->dfs();
}
if(rc){
rv = rc->dfs();
}
sz = ((lc)? lc->sz:0) + ((rc)? rc->sz:0) + 1;
return max(1LL * sz * value, max(lv, rv));
}
void clear(){
while(!st.empty()){
st.pop();
}
memory = pool;
root = NULL;
}
int main(){
int n, i, x;
while(1){
clear();
scanf("%d", &n);
if(n == 0)break;
for(i = 1; i <= n; i++){
scanf("%d", &x);
insert(x);
}
printf("%lld\n", root->dfs());
}
return 0;
}