抽象一下问题,现在给出输入数组 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; }