题目链接
又花式水过了一题,正解不知道是啥,可能很高端的样子。
题意
有
N
个数,某个子区间的价值为这个区间内最大值*最小值。
求长度为1的所有子区间中价值最大的那个是多少
求长度为2的所有了区间中价值最大的那个是多少
…
求长度为
思路
pre: maxRange[i]表示区间长度为i的所有区间中价值最大那个值。
把数从大到小排个序,准备一个空序列,然后依次加入序列中,那么对于当前加入的数x,已经出现的数一定大于等于x,假设位置为p,算出向左至pl,向右至pr,这个区间 [pl,pr] 是已经加入了的,也就是说这些数都>=x,所以这个区间的价值为 val=x∗max(Apl...Apr) 。这个区间长度为 len=pr−pl+1 ,更新 maxRangelen=max(maxRangelen,val) .
最后输出答案 anweri=max(maxRangei...n) .这里为什么成立呢,因为当我们加入一个数算出区间长度为k,价值为v,那么这个区间的子区间(长度小于k)的价值一定大于等于v…
所以我们用个线段树啥的,查询一下区间最大值就可以了,计算两边位置 pl 和 pr ,可以用dp来写,我用了两个并查集来更新每个位置的 pl 和 pr 。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#define DEFMID int mid = l + r >> 1
#define L_SON (v << 1)
#define R_SON (v << 1 | 1)
#define L_RANGE l, mid
#define R_RANGE mid + 1, r
typedef long long LLONG;
typedef unsigned long long ULLONG;
typedef std::pair<int, int> PII;
typedef std::vector<int> VI;
#define debug(x) std::cout << #x << " = " << x << std::endl;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int A[N];
int C[N]; //是否已经加入
PII stA[N]; //用于排序用
int maxTree[N << 2];
LLONG maxRange[N];
LLONG answer[N];
inline void pushUp(int v) {
maxTree[v] = std::max(maxTree[L_SON] , maxTree[R_SON]);
}
inline void build(int l, int r, int v) {
if (l >= r) {
maxTree[v] = A[l];
return;
}
DEFMID;
build(L_RANGE, L_SON);
build(R_RANGE, R_SON);
pushUp(v);
}
inline int query(int l, int r, int x, int y, int v) {
if (l >= x && r <= y) {
return maxTree[v];
}
DEFMID;
int rlt = 0;
if (mid >= x) rlt = query(L_RANGE, x, y, L_SON);
if (mid < y) rlt = std::max(rlt, query(R_RANGE, x, y, R_SON));
return rlt;
}
int rootLeft[N]; //向左pl
int rootRight[N]; //向右pr
inline int findSet(int root[], int x) {
return root[x] = root[x] == x ? x : findSet(root, root[x]);
}
inline void unionSetLeft(int u) {
if (~C[u + 1]) {
int v = findSet(rootRight, u + 1);
rootRight[u] = v;
}
if (~C[u - 1]) {
int v = findSet(rootLeft, u - 1);
rootLeft[u] = v;
}
if (~C[u + 1]) {
int v = findSet(rootLeft, u);
rootLeft[u + 1] = v;
}
if (~C[u - 1]) {
int v = findSet(rootRight, u);
rootRight[u - 1] = v;
}
}
int main() {
int n, m;
for (; ~scanf("%d", &n);) {
for (int i = 0; i <= n + 1; ++i) {
rootLeft[i] = i;
rootRight[i] = i;
C[i] = -1;
maxRange[i] = -1;
}
for (int i = 1; i <= n; ++i) {
scanf("%d", A + i);
stA[i] = std::make_pair(A[i], i);
}
std::sort(stA + 1, stA + n + 1);
build(1, n, 1);
for (int i = n; i > 0; --i) {
unionSetLeft(stA[i].second);
int left = findSet(rootLeft, stA[i].second);
int rit = findSet(rootRight, stA[i].second);
int tmpMax = query(1, n, left, rit, 1);
maxRange[rit - left + 1] = std::max(1LL * tmpMax * stA[i].first, maxRange[rit - left + 1]);
C[stA[i].second] = 1;
}
int cur = n;
for (int i = n; i > 0; --i) {
if (maxRange[i] > maxRange[cur]) cur = i;
answer[i] = maxRange[cur];
}
for (int i = 1; i <= n; ++i) {
printf("%I64d\n", answer[i]);
}
}
return 0;
}
/*
1 6 4 4 2 4 4
*/