POJ2559 HDU1506 ZOJ1985 Largest Rectangle in a Histogram

vjudge传送

题解:

本题很妙,有多种方法求解。我讲常见的4种做法。

解法1: 暴力求解(只是看似暴力)

我们记录 l e f t [ i ] left[i] r i g h t [ i ] right[i] 分别表示i这个位置最左和最右能到的位置,则答案为( r i g h t [ i ] right[i] - l e f t [ i ] left[i] + 1) * h[i] 的最大值;(注意开long long)
至于求 l e f t [ i ] left[i] r i g h t [ 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] 的求法, r i g h t [ i ] right[i] 同理。

代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdio>
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;
}
解法2:单调栈

在这个单调栈中,维护最小值。每次入栈需要放入一个pair,first 存储值,second存储位置。当一个pair弹出并且枚举到 i 时,说明i的高度比这个大(所以弹出)
这个位置的高度最右能到达i - 1,
最左能到达弹出后栈顶元素的位置加一。
每次更新最大值。记住最后将高度为 0 的加入。弹出剩余的。

代码如下:
#include <iostream>
#include <cstdio>
#include <utility>
#include <stack>
#include <algorithm>
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;
}
解法3:RMQ - ST表变形

先求出所有位置中高度最低的(用ST表找出),用它的长度 * 总长度来更新答案;
然后以这个点分成2段,递归求解。

代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string> 
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;
}
解法4:笛卡尔树

根据原数组,借助栈建一棵笛卡尔树,所以,每次只需用 每个子树的大小 * 该子树根结点的点权 来更新答案

代码如下:
#include <iostream>
#include <cstdio>
#include <stack>
#include <cstdio>
#include <algorithm>
#include <map>
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;
}

猜你喜欢

转载自blog.csdn.net/linwenqidbk/article/details/96617124
今日推荐