洛谷 P7726 天体探测仪(Astral Detector) 题解
一、题目:
二、思路:
个人感觉这道题还是比较有意思的。我当时想了一段时间,发现了很多性质,但是就是想不出一个可以通用的算法。
我们首先可以对于每个 \(i\),确定出以它为最小值的最长区间的长度 \(len_i\)。咋确定呢?可以发现 \(len_i\) 等于最大的、使得 \(S_k\) 中包含元素 \(i\) 的 \(k\)。
考虑如果确定下来 \(len_i\),那么该如何确定 \(i\) 在区间中的位置。如果所有长度为 \(k\) 的区间都包含 \(i\) 的话,那么 \(i\) 出现的次数应该等于 \(len_i-k+1\)。所以,\(i\) 到区间左端点的距离就等于最大的、使得 \(i\) 出现次数不是 \(len_i-k+1\) 的 \(k\)。
有些同学可能会问,为什么必须是到区间“左端点”,为什么不能是区间右端点?事实上也是可以的,左右端点实际上是等价的。
确定完所有 \(i\) 的 \(len_i\) 以及在区间中的出现位置之后,我们考虑该如何确定下来区间的具体位置。我们可以对于每个 \(j\),维护队列 \(q_j\),表示所有长度为 \(j\) 的可用区间的左端点。每次按需拿去用一个,分裂开,存储到对应的区间中即可。
三、代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define FILEIN(s) freopen(s, "r", stdin)
#define FILEOUT(s) freopen(s, "w", stdout)
#define mem(s, v) memset(s, v, sizeof s)
inline int read(void) {
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return f * x;
}
const int MAXN = 805;
int n, ans[MAXN];
int cnt[MAXN][MAXN];
queue<int>q[MAXN];
int main() {
n = read();
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= n - i + 1; ++ j) {
int x = read();
++ cnt[i][x];
}
}
q[n].push(1);
for (int x = 1; x <= n; ++ x) {
int len = 0;
for (int i = n; i >= 1; -- i)
if (cnt[i][x] > 0) { len = i; break; }
int k = 0;
for (int j = 1; j <= len; ++ j)
if (cnt[j][x] == len - j + 1) { k = j - 1; break; }
int l = q[len].front(); q[len].pop();
ans[l + k] = x;
if (k > 0) q[k].push(l);
if (len - k - 1 > 0) q[len - k - 1].push(l + k + 1);
}
for (int i = 1; i <= n; ++ i) printf("%d ", ans[i]);
puts("");
return 0;
}