Codeforce 547B - Mike and Feet

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Cymbals/article/details/83861710

题意:给定一个数组,对于这个数组构造n个长度为1到n的区间,要求最小值最大,输出构造区间的最小值。

转换一下题意,可以求每一个数字是多长区间的最小值。
先正着求这个数字的左半边覆盖长度,再倒着求右半边覆盖长度。

然后用r - l + 1算出区间长度,对于该长度的区间取最大值。

这样搞很显然会有许多区间还没有答案,但是我们可以想到,长的区间都有答案,那短的区间也会有答案,短的区间的答案只会大于等于长的区间。因此可以用长的区间去更新短的区间。

这样复杂度可能会去到 O ( n ² ) O(n²) 。但是根据上面的结论,即短区间的答案只会大于等于长区间,所以答案序列一定是一个单调递减的序列,所以我们可以直接从后往前更新最大值。

嗯,后缀自动机经常这么干,没想到用到了这里。

ac代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;
int n, a[maxn];
int l[maxn], r[maxn];
int ans[maxn];

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	for(int i = 1; i <= n; i++) {
		l[i] = i;
		while(a[l[i] - 1] >= a[i]) {
			l[i] = l[l[i] - 1];
		}
	}
	for(int i = n; i >= 1; i--) {
		r[i] = i;
		while(a[r[i] + 1] >= a[i]) {
			r[i] = r[r[i] + 1];
		}
	}
	for(int i = 1; i <= n; i++) {
		int e = r[i] - l[i] + 1;
		ans[e] = max(ans[e], a[i]);
	}
	for(int i = n - 1; i >= 1; i--) {
		ans[i] = max(ans[i], ans[i + 1]);
	}
	for(int i = 1; i <= n; i++) {
		printf("%d ", ans[i]);
	}
	printf("\n");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Cymbals/article/details/83861710