洛谷 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;
}

posted @ 2021-07-14 21:37  蓝田日暖玉生烟  阅读(121)  评论(0编辑  收藏  举报