CF1450D 排名压缩

1 CF1450D 排名压缩

2 题目描述

在竞赛编程平台 \(CodeCook\) 上,每个人都有一个由长度为 \(n\) 的整数数组 \(a\) 表示的评级图。现在要更新系统,需要写一个程序来压缩这些评级图。
程序是这么工作的,给定一个整数参数 \(𝑘\),程序取 \(𝑎\) 中每个长度为 \(𝑘\) 的连续子数组的最小值。
更具体地说,对于长度为 \(𝑛\) 的数组 \(𝑎\) 和整数 \(𝑘\),将 \(𝑎\)\(𝑘\) 压缩数组定义为长度为 \(n-k+1\) 的数组 \(𝑏\),这样
\(𝑏_𝑗=\underset{j≤i≤j+k-1}{min}𝑎_𝑖\)
例如,\([1,3,4,5,2]\)\(3\) 压缩数组是 \([min\){1,3,4}\(,min\){3,4,5}\(,min\){4,5,2}\(]=[1,3,2]\)
长度 \(𝑚\) 的排列是一个由 \(𝑚\) 个从 \(1\)\(𝑚\) 的不同整数按任意顺序组成的数组。例如,\([2,3,1,5,4]\) 是置换,但 \([1,2,2]\) 不是置换(\(2\) 在数组中出现了两次),\([1,3,4]\) 也不是置换(\(𝑚=3\) 但数组中有 \(4\))。
一个 \(𝑘\) 压缩数组如果是一个全排列序列,\(CodeCook\) 的用户会很高兴。给定一个数组 \(𝑎\),确定所有 \(1≤𝑘≤𝑛\)\(CodeCook\) 用户是否会在此数组的 \(𝑘\) 压缩后感到高兴。

3 解题思路

我们仔细分析性质:在第 \(k\) 种压缩中,如果我们想要满足整个序列为全排列序列,那么这个全排列中涉及的数是 \(1\)\(n-k+1\)。然后我们发现,一个序列想要满足全排列,必须满足以下性质:最小的数只能出现一次且必须出现在边界。否则这个数就会被重复计算,导致答案不是全排列形式。而且通过分析样例,我们得到:如果第 \(k\) 种压缩是全排列形式,那么所有大于 \(k\) 的排列也都是全排列形式。这是因为在 \(k\) 的增大过程中,压缩序列中的数越来越少。如果第 \(k\) 种压缩是全排列方式,那么说明最小的数都在边缘,向中间的数逐渐增大。如果我们在这时给所有的子序列长度都 \(+1\),那么原本的最小数不会消失,反而是最大的数被次大的数覆盖了。

于是我们得到算法:\(i\)(数字)从 \(1\) 枚举到 \(n\),每次看它是否存在。如果存在,那么第 \(n-i+1\) 种压缩成立,否则直接跳出。接下来看如果最小值的个数大于 \(1\) 或者最小值的位置不在边缘,那么下一次便不成立了,跳出。

注意要特判 \(1\)\(n\) 的情况。

4 代码(空格警告):

#include <iostream>
#include <deque>
using namespace std;
const int N = 3e5+10;
int T, n, flag, flag2, k;
int a[N], ans[N], cnt[N];
deque<int> q;
int main()
{
    cin >> T;
    while (T--)
    {
        while (q.size()) q.pop_back();
        flag = 1;
        flag2 = 0;
        cin >> n;
        for (int i = 1; i <= n; i++) cnt[i] = 0, ans[i] = 0;
        for (int i = 1; i <= n; i++)
        {
            cin >> a[i];
            if (a[i] == 1) flag2 = 1;
            if (cnt[a[i]]) flag = 0;
            cnt[a[i]]++;
            q.push_back(a[i]);
        }
        for (int i = 1; i <= n; i++)
        {
            k = n - i + 1;
            if (!cnt[i]) break;
            cnt[i]--;
            ans[k] = 1;
            if (cnt[i]) break;
            if (q.front() == i) q.pop_front();
            else if (q.back() == i) q.pop_back();
            else break;
        }
        ans[1] = flag;
        ans[n] = flag2;
        for (int i = 1; i <= n; i++) cout << ans[i];
        puts("");
    }
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-02-05 16:35  David24  阅读(48)  评论(0编辑  收藏  举报