POJ2452_Sticks Problem

题意:

给你一组数a[n],求满足a[i] < a[k] < a[j] (i <= k <= j)的最大的区间长度 j - i

解法1:O(n^2)

先记录每一位数A[i]后面连续大于这个数的长度len[i],然后再这个长度里[i, i+len[i] )找最大的数的下标 j,这样可求得最大的区间 j - i

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 50000+5;
using namespace std;
int n, A[maxn];
int len[maxn];	// len[i]: 大于 A[i] 的连续最大长度

int main()
{
    freopen("in.txt","r",stdin);
    
	while(scanf("%d",&n) == 1){
		for(int i = 1; i <= n; ++i){
			scanf("%d", &A[i]);
			len[i] = 1;
		}
		for(int i = n; i >= 1; --i){
			while(i+len[i] <= n&&A[i] < A[i+len[i]]) len[i]+= len[i+len[i]];
		}
		int ans = -1;
		for(int i = 1; i <= n; ++i){
			int r = -1, tmp = -1;
			for(int j = 1; j < len[i]; ++j){
				if(r < A[i+j]){
					r = A[i+j];
					tmp = j;
				}
			}
			ans = max(ans, tmp);
		}
		printf("%d\n", ans);
	}
    fclose(stdin);
	return 0;
}

解法2:RMQ+二分O(nlogn)

枚举i,利用二分求出a[i]右边第一个小于a[i]的数的位置k,
再求出[i, k]中最大值的位置j,若a[j] > a[i],则更新结果

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 50000+5;
using namespace std;
int n, A[maxn];
int maxval[maxn][20], minval[maxn][20];

int max1(int i, int j){
	if(A[i] > A[j]) return i;
	return j;
}
int min1(int i, int j){
	if(A[i] < A[j]) return i;
	return j;
}

void ST(){
	for(int i = 1; i <= n; ++i) maxval[i][0] = minval[i][0] = i;
	for(int i = 1; i <= log2(n); ++i){
		for(int j = 1; j + (1<<i) - 1 <= n; ++j){
			maxval[j][i] = max1(maxval[j][i-1], maxval[j + (1<<i-1)][i-1]);
			minval[j][i] = min1(minval[j][i-1], minval[j + (1<<i-1)][i-1]);
		}
	}
}
int Query_max(int l, int r){
	int k = log2(r-l+1);
	return max1(maxval[l][k], maxval[r-(1<<k)+1][k]);
}
int Query_min(int l, int r){
	int k = log2(r-l+1);
	return min1(minval[l][k], minval[r-(1<<k)+1][k]);
}

int bsearch(int l, int r, int x){
	while(l < r){
		int mid = (l+r) >> 1;
		if(A[Query_min(l, mid)] > A[x]) l = mid + 1;
		else r = mid;
	}
	return l;
}

void solve(){
	int ans = -1;
	for(int i = 1; i <= n; ++i){
		int k = bsearch(i+1, n, i);
		int j = Query_max(i, k);
		if(A[j] > A[i]) ans = max(ans, j - i);
	}
	printf("%d\n", ans);
} 

int main()
{
    freopen("in.txt","r",stdin);
    
	while(scanf("%d",&n) == 1){
		for(int i = 1; i <= n; ++i) scanf("%d", &A[i]);
		ST();
		solve();
	}
    fclose(stdin);
	return 0;
}

解法3:单调栈O(n)

在discuss区看到大佬发的,复制下来学习。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct node{int low,high,id1,id2;}p,stack[50055];
int i,ans,top,x,n;
int main()
{
	//freopen("in.txt", "r", stdin); 
	while(scanf("%d",&n) == 1)
	{
		top = ans = 0;
		for(i = 1; i <= n; ++i)
		{
			scanf("%d",&x);	
			if(x > stack[top].high&&top)
			{
				while(x > stack[top].high&&top) p = stack[top--], ans = max(ans, p.id2 - p.id1);
				p.high = x; p.id2 = i; stack[++top] = p;
			}
			else if(x < stack[top].low&&top)
			{
				while(x < stack[top].low) p = stack[top--], ans = max(ans, p.id2 - p.id1);
				p.low = p.high = x; p.id1 = p.id2 = i; stack[++top] = p;
			}
			else
			{
				p.low = p.high = x; p.id1 = p.id2 = i;
				stack[++top] = p;
			}
		}
		while(top) p = stack[top--], ans = max(ans, p.id2 - p.id1);
		printf(!ans?"-1\n":"%d\n",ans); 
	}
	fclose(stdin);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值