• 【每日一题】补档 CF1799C. Double Lexicographically Minimum | 构造 | 简单


    题目内容

    原题链接

    给定一个长度为 n n n 的只有小写字母的字符串 s s s ,随意排列这个字符串,使得字符串正着和反着的最大字典序最小。

    数据范围

    • 1 ≤ n ≤ 1 0 5 1\leq n\leq 10^5 1n105
    • s s s 中都是小写字母

    题解

    我们保证首尾字符尽可能相等,且字符尽可能小。

    统计每个字符的出现次数。

    记录最小字符 a a a 出现了 c a ca ca 次,大于最小字符 a a a 的字符 b b b 出现了 c b cb cb 次,大于 b b b 的字符 c c c 出现了 c c cc cc 次。

    • c a = 1 , c b = 0 ca=1,cb=0 ca=1,cb=0 ,那么直接放
    • c a ≥ 2 ca\geq 2 ca2 ,那么首尾放 a a a 即可
    • c a = 1 , c b = 1 ca=1,cb=1 ca=1,cb=1 ,那么一边放 a a a 一边放 c c c 即可,剩余部分从 c c c 一边开始从小到大放
    • c a = 1 , c b > 1 ca=1,cb>1 ca=1,cb>1
      • c c = 0 cc=0 cc=0 ,那么两边放 b b b,把 a a a 留在最中间
      • c c > 0 cc>0 cc>0 ,那么一边放 a a a 一边放 b b b,剩余部分从 b b b 一边开始从小到大放。
        c c > 0 cc>0 cc>0 如果不放 a a a ,那就是放两个 b b b
        考虑放 a a a 与不放 a a a ,对于 a a a 这边来说不是决定最大字典序的模块,放了 a a a ,我就可以将剩余字符都按从小到大的顺序给 b b b 一边。但是如果不放 a a a ,我就要拿两个 b b b 放到两边,本来我的最小的是 b b . . . c c . . . d d . . . bb...cc...dd... bb...cc...dd... 这种形式,现在少了一个就成了 b c c . . . d d . . . bcc...dd... bcc...dd... 。那么这个 a a a 放到哪,后面一定是接一个从最大字符到最小字符的。但是我本来是 b b c c . . . d d . . . bbcc...dd... bbcc...dd... 的形式,变成了 b c c . . . d d . . . bcc...dd... bcc...dd... 形式,字典序就变大了,所以此时是一边放 a a a 一边放 b b b 最优解。

    代码,

    #include 
    using namespace std;
    
    const int N = 100010;
    char s[N];
    char ans[N];
    int cnt[26];
    int n;
    
    void op(int& x, int& y, int i, int j) {
        ans[x] = i + 'a';
        ans[y] = j + 'a';
        cnt[i] -= 1;
        cnt[j] -= 1;
        x += 1;
        y -= 1;
    }
    
    void solve() {
        memset(cnt, 0, sizeof cnt);
        scanf("%s", s + 1);
        n = strlen(s + 1);
    
        if (n == 1) {
            puts(s + 1);
            return ;
        }
    
        for (int i = 1; i <= n; ++i) {
            cnt[s[i] - 'a'] += 1;
        }
    
        ans[n + 1] = 0;
        int i = 1, j = n;
        while (i < j) {
            int id[3] = {-1, -1, -1};
            for (int c = 0; c < 26; ++c) {
                if (cnt[c] > 0) {
                    if (id[0] == -1) id[0] = c;
                    else if (id[1] == -1) id[1] = c;
                    else if (id[2] == -1) id[2] = c;
                    else break;
                }
            }
    
            if (id[0] != -1 && cnt[id[0]] >= 2) {
                op(i, j, id[0], id[0]);
                continue ;
            }
    
            if (id[0] != -1 && id[1] != -1 && cnt[id[0]] == 1 && cnt[id[1]] == 1) {
                op(i, j, id[0], id[1]);
                break;
            }
    
            if (id[2] == -1 && cnt[id[1]] >= 2) {
                op(i, j, id[1], id[1]);
                continue ;
            } else {
                op(i, j, id[0], id[1]);
                break;
            }
        }
    
        for (int k = i, c = 25; k <= j; ++k) {
            while (c > 0 && cnt[c] == 0) c -= 1;
            ans[k] = c + 'a';
            cnt[c] -= 1;
        }
    
        reverse(ans + 1, ans + n + 1);
    
        printf("%s\n", ans + 1);
    }
    
    int main()
    {
        int T = 1;
        scanf("%d", &T);
        while (T--) {
            solve();
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
  • 相关阅读:
    Ubuntu - 网络
    MapReduce
    代码随想录算法训练营day53 | 1143.最长公共子序列,1035.不相交的线,53. 最大子序和
    限量版Spring实战笔记与其在收藏里吃灰,不如大家一起学习,欸 大家一起卷!
    2023/10/05 部分汇编指令
    C# 设计模式 结构型模式 之 适配器模式
    2000-2019年中国灌溉耕地分布数据集
    C++对象内存布局
    graphhopper-ios 编译过程详解
    北理工嵩天Python语言程序设计笔记(10 Python计算生态概览)
  • 原文地址:https://blog.csdn.net/weixin_43900869/article/details/134078985