题意:
抽象一下问题,现在给出输入数组 a,
定义 ax 可以被 al 和 ar 插值得到为:
存在 l < x < r
使得 al ≤ ax ≤ ar 或者 al ≥ ax ≥ ar。
求最少的「锚固」(固定)元素的数目,使得非锚固元素都可以由其左右最靠近它的锚固元素插值得到。并输出锚固元素的下标。
思路:
先找到整个数组的最大值和最小值,假设最小值角标 i 小于最大值角标 j ,我们必须要先固定 i 和 j ,因为这两个位置不可能通过其它的位置来固定,题目保证 ai 各不相同,所以 固定i 和 j 之后,i 和 j 之间的位置也就固定好了,,现在来考虑 j 之后的位置。对于j之后的位置,我们要考虑[j+1, n]区间的最小值,,然后固定最小值,在考虑最小值之后的位置,找最大值,固定最大值,考虑最大值之后的位置,,如此反复到数组右端。。数组左半段同理。
用ST算法求最值即可。
代码写的有点挫。。^_^
#pragma warning(disable:4996)
#include <cstdio>
#include <map>
#include <vector>
#include <algorithm>
#define N 100010
using namespace std;
int maxn[N][20], minn[N][20], a[N], n;
vector<int>ans;
map<int, int>mp;
void RMQ(){
for (int i = 1; i <= n; i++)maxn[i][0] = minn[i][0] = a[i];
for (int j = 1; j < 20; j++){
for (int i = 1; i <= n; i++){
int r = i + (1 << (j - 1));
if (r <= n){
maxn[i][j] = max(maxn[i][j - 1], maxn[r][j - 1]);
minn[i][j] = min(minn[i][j - 1], minn[r][j - 1]);
}
}
}
}
int query(int l, int r, int type){
int base = 0;
while ((1 << (base + 1)) < (r - l + 1))base++;
if (type == 1)return mp[max(maxn[l][base], maxn[r + 1 - (1 << base)][base])];
else return mp[min(minn[l][base], minn[r + 1 - (1 << base)][base])];
}
int main(){
scanf("%d", &n);
for (int i = 1; i <= n; i++){
scanf("%d", a + i);
mp[a[i]] = i;
}
RMQ();
int i, j, x, y;
x = query(1, n, 1);
y = query(1, n, 2);
if (x < y){
ans.push_back(x);
while (1){
if (x>1){
x = query(1, x - 1, 2);
ans.push_back(x);
}
else break;
if (x > 1){
x = query(1, x - 1, 1);
ans.push_back(x);
}
else break;
}
ans.push_back(y);
while (1){
if (y<n){
y = query(y + 1, n, 1);
ans.push_back(y);
}
else break;
if (y < n){
y = query(y + 1, n, 2);
ans.push_back(y);
}
else break;
}
}
else{
int tmp = x;
x = y;
y = tmp;
ans.push_back(x);
while (1){
if (x>1){
x = query(1, x - 1, 1);
ans.push_back(x);
}
else break;
if (x > 1){
x = query(1, x - 1, 2);
ans.push_back(x);
}
else break;
}
ans.push_back(y);
while (1){
if (y<n){
y = query(y + 1, n, 2);
ans.push_back(y);
}
else break;
if (y < n){
y = query(y + 1, n, 1);
ans.push_back(y);
}
else break;
}
}
sort(ans.begin(), ans.end());
printf("%d\n%d", ans.size(), ans[0]);
for (int i = 1; i < ans.size(); i++)printf(" %d", ans[i]);
puts("");
return 0;
}