CF1032C Playing Piano

CF1032C Playing Piano - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目大意是:能否构造一个长度为 nn 的值域为 [1,5][1, 5] 的整数序列 bb,使得相邻两个数之间的大小关系满足给定的大小关系。

给定的大小关系可能是大于、小于、不等于。

CF 官方给的 dp 做法是假的。实际上只需要一个橙色难度的简单构造。而且这个做法时空复杂度和 bb 的值域完全无关。dp 就相对受限了。

把序列拆分为连续大于段,连续小于段和连续不等段。

贪心地,连续大于段从 55 开始,填 (5,4,3,2,1)(5, 4, 3, 2, 1)。连续小于段从 11 开始,填 (1,2,3,4,5)(1, 2, 3, 4, 5)。填不下去了就是连续长度大于 55 了,报个无解。

连续不等段直接在 2,32, 3 之间振荡。3,43, 4 之间,2,42, 4 之间也可以,但不要涉及到 1,51, 5,看后面就知道原因了。

然后考虑一下段和段的边界。

先小于后大于 a<b<c>d>ea < b < c > d > e。发现 cc 明显应该填 55,也就是跟随后面那个段,因为要让后面尽可能连续下去。按照上面的贪心填法对应的构造方案是 (1,2,5,4,3)(1, 2, 5, 4, 3)

先大于后小于同理,跟后面。

先不等后小于 abc<d<ea \ne b \ne c < d < e。会发现 cc 应该填 11 最好,也是跟随后面。这里就是为什么不等段的振荡最好不涉及 1155,否则可能影响边界。

先不等后大于同理,跟后面。

先小于后不等 a<b<cdea < b < c \ne d \ne e,这个 cc 应该跟前面。

先大于后不等同理,跟前面。

但是这样会有一个问题:>a>b>cd<e<f<\cdots > a > b > c \ne d < e < f < \cdotsdd 应该怎么填?如果 cc 没填 11 自然老办法 dd11,如果 cc 填了 11 呢?

不难发现,此时 dd 只能填 22。因为根据我们的贪心想法,cc 此时都为 11 了就说明前面必有一段 5>4>3>2>15 > 4 > 3 >2 >1 的链,将 cc 修改为 22 前面就会不合法。大小于号翻过来后情况也是类似的。

注意 n=1n = 1 可能需要特判,根据你咋写的。

复杂度 Θ(n)\Theta(n)

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2023-01-07 01:36:54 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2023-01-07 02:23:00
 */
#include <bits/stdc++.h>
inline int read() {
    int x = 0;
    bool f = true;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar())
        if (ch == '-')
            f = false;
    for (; isdigit(ch); ch = getchar())
        x = (x << 1) + (x << 3) + ch - '0';
    return f ? x : (~(x - 1));
}

const int maxn = (int)1e5 + 5;

int a[maxn];
char b[maxn]; // b[i] 表示 b[i] 和 b[i + 1] 的大小关系

int main() {
    int n = read();
    if (n == 1) {
        puts("1");
        return 0;
    }
    
    for (int i = 1; i <= n; ++i)
        a[i] = read();
    for (int i = 1; i < n; ++i) {
        if (a[i] < a[i + 1])
            b[i] = '<';
        else if (a[i] > a[i + 1])
            b[i] = '>';
        else
            b[i] = '!';
    }
    
    int lst = 1;
    if (b[1] == '>')
        lst = 5;
    else if (b[1] == '!')
        lst = 2;
    
    std :: vector <int> ans = {lst};
    
    for (int i = 2; i < n; ++i) {
        int now;
        char p = b[i - 1], q = b[i];
        if (p == '<') {
            if (lst == 5)
                break;
            now = lst + 1;
            if (q == '>')
                now = 5;
        } else if (p == '>') {
            if (lst == 1)
                break;
            now = lst - 1;
            if (q == '<')
                now = 1;
        } else if (p == '!') {
            if (q == '!') {
                now = 3;
                if (lst == 3)
                    now = 2;
            } else if (q == '<') {
                now = 1;
                if (lst == 1)
                    now = 2;
            } else if (q == '>') {
                now = 5;
                if (lst == 5)
                    now = 4;
            }
        }

        ans.push_back(lst = now);
    }

    if (b[n - 1] == '<')
        ans.push_back(5);
    else if (b[n - 1] == '>')
        ans.push_back(1);
    else
        ans.push_back(lst == 5 ? 4 : 5);
    
    if ((int)ans.size() == n)
        for (int x : ans)
            printf("%d ", x);
    else
        printf("-1");
    puts("");
    return 0;
}
posted @   dbxxx  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示