• CF1455F. String and Operations Edu Round 99. 贪心


    Edu Round 99 F. String and Operations

    在这里插入图片描述
    在这里插入图片描述

    题目链接:https://codeforces.com/contest/1455/problem/F

    (t)组数据,给你一个长度为(n)由前(k)个字符组成的字符串。第(i)次操作你可以对原本在位置(i)的字符做(4)种操作中的一种或者不操作。

    • (L:) 若前面有字符就和前面的一个交换位置;
    • (R:) 若后面有字符就和后面的一个交换位置;
    • (D:) 循环左移一位,如:(b ightarrow a,a ightarrow k_{-th};character)
    • (U:) 循环右移一位,如:(a ightarrow b,k_{-th};character ightarrow a)

    求经过(n)次操作后可以得到的字典序最小的字符串。

    对上述操作的解释如下:

    字符串为testk=20经过操作URLD后字符串变成:(test ightarrow aest ightarrow aset ightarrow saet ightarrow saes)

    输入:
    6
    4 2
    bbab
    7 5
    cceddda
    6 5
    ecdaed
    7 4
    dcdbdaa
    8 3
    ccabbaca
    5 7
    eabba
    输出:
    aaaa
    baccacd
    aabdac
    aabacad
    aaaaaaaa
    abadb
    

    思路

    观察知道,一个字符最多可以向前移动(2)个位置。比如(abc),第一次不操作,第二次操作(R),第三次操作(L)后就变成了(cab)

    但是要将位置(i+2)的字符移动到位置(i)的话,它是没办法通过循环移动再变小的。

    不过将位置(i+1)的字符移动到位置(i)的话, 他是可以做一次循环移动的,第一次操作(R),第二次操作(D;or;U)

    那我们就贪心考虑每一位可能变换的最小值是多少。

    假设经过合法改变后:现在在位置(i)的字符可以变成的最小字符为(x),现在在位置(i+1)的字符变到位置(i)后可以变成的最小字符为(y),现在在位置(i+2)的字符变到位置(i)后可以变成的最小字符为(z)

    如果(xle y &xle z)的话,位置(i)肯定还在位置(i)

    如果(ylt x& yle z)的话,位置(i+1)字符肯定是要移动到位置(i)的。

    如果(zlt x& zlt y)的话,位置(i+2)字符肯定是要移动到位置(i)的。

    到这里都是铺垫,下面来讲具体做法:

    (origin[i]=0) 表示(i)位置的字符原本就在(i)
    (down[i]=0) 表示(i)位置的字符能进行循环移动。

    • 如果(i+1)的字符能移动到(i),需要保证位置(i+1)字符原本就在(i+1)
    • 如果(i+2)的字符能移动到(i),需要保证位置(i+1)字符原本就在(i+1)
    • 然后再根据(down[i])(down[i+1])求出(x,y,z)的结果。
    • 然后再根据相应的(x,y,z)大小改变(origin[i+1],origin[i+2],down[i+1],down[i+2]),详见代码注释。
    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define o2(x) (x) * (x)
    #define mk make_pair
    #define eb emplace_back
    #define SZ(x) ((int)(x).size())
    #define all(x) (x).begin(), (x).end()
    #define clr(a, b) memset((a), (b), sizeof((a)))
    #define rep(i, s, t) for(register int i = (s), LIM=(t); i < LIM; ++i)
    #define per(i, s, t) for(register int i = (s), LIM=(t); i >= LIM; --i)
    #define GKD std::ios::sync_with_stdio(false);cin.tie(0)
    #define my_unique(x) sort(all(x)), x.erase(unique(all(x)), x.end())
    using namespace std;
    typedef long long LL;
    typedef long long int64;
    typedef unsigned long long uint64;
    typedef pair<int, int> pii;
    // mt19937 rng(time(NULL));//std::clock()
    // mt19937_64 rng64(chrono::steady_clock::now().time_since_epoch().count());
    // shuffle(arr, arr + n, rng64);
    inline int64 read() {
        int64 x = 0;int f = 0;char ch = getchar();
        while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
        while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch =
        getchar(); return x = f ? -x : x;
    }
    inline void write(int64 x, bool f = true) {
        if (x == 0) {putchar('0'); if(f)putchar('
    ');else putchar(' ');return;}
        if (x < 0) {putchar('-');x = -x;}
        static char s[23];
        int l = 0;
        while (x != 0)s[l++] = x % 10 + 48, x /= 10;
        while (l)putchar(s[--l]);
        if(f)putchar('
    ');else putchar(' ');
    }
    int lowbit(int x) { return x & (-x); }
    template <class T>
    T big(const T &a1, const T &a2) {return a1 > a2 ? a1 : a2;}
    template <class T>
    T sml(const T &a1, const T &a2) {return a1 < a2 ? a1 : a2;}
    template <typename T, typename... R>
    T big(const T &f, const R &... r) {return big(f, big(r...));}
    template <typename T, typename... R>
    T sml(const T &f, const R &... r) {return sml(f, sml(r...));}
    void debug_out() { cout << '
    '; }
    template <typename T, typename... R>
    void debug_out(const T &f, const R &... r) {
        cout << f << " ";
        debug_out(r...);
    }
    #ifdef LH_LOCAL
    #define debug(...) cout << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);
    #else
    #define debug(...) ;
    #endif
    /*================Header Template==============*/
    const int mod = 998244353;// 998244353
    int ksm(int a, int64 b, int kmod = mod) {int res = 1;for(;b > 0;b >>= 1, a = (int64)a * a % kmod) if(b &1) res = (int64)res * a % kmod;return res;}
    const int INF = 0x3f3f3f3f;
    const int MXN = 2e5 + 5;
    
    int n, m;
    char s[MXN];
    int ori[MXN], dwn[MXN];
    /*
    origin[i] 表示i位置的字符是否原本就在i。
    down[i] 表示i位置的字符能否循环移动。
    如果i+1的字符能移动到i,需要保证i+1原本就在i+1。
    如果i+2的字符能移动到i,需要保证i+1原本就在i+1。
    如果经过合法改变后,从i来的字符是最小的就选i位置保持不变,否则如果从i+1来的字符是最小的就选i+1位置,否则如果从i+2来的字符是最小的就选i+2位置,否则就不变。
    */
    void work() {
        n = read(), m = read();
        rep(i, 0, n) ori[i] = dwn[i] = 0;
        scanf("%s", s);
        rep(i, 0, n) {
            int a = s[i] - 'a', b = (i + 1 < n && ori[i + 1] == 0? s[i + 1] - 'a': INF), c = (i + 2 < n && ori[i + 1] == 0? s[i + 2] - 'a': INF);
            //位置i可以循环移动
            if(dwn[i] == 0) a = sml(a, (a + 1) % m, (a + m - 1) % m);
            //位置i+1可以循环移动
            if(b != INF && ori[i] == 0 && dwn[i + 1] == 0 && ori[i + 1] == 0) b = sml(b, (b + 1) % m, (b + m - 1) % m);
            if(a <= b && a <= c) {
                s[i] = a + 'a';
            }else if(b <= a && b <= c) {
                swap(s[i], s[i + 1]);
                if(s[i] != b + 'a') {//这时候i要必须先做操作R,所以改变后i+1没法循环移动
                    s[i] = b + 'a';
                    dwn[i + 1] = 1;
                }else {
                    //这时候i+1位置是不需要经过循环移动来变成更小的元素的,所以i位置是可能保留了一次操作,先不要急着操作,后面再慢慢考虑。
                }
                if(dwn[i]) dwn[i + 1] = 1;//但是如果原本i本来就没法循环移动,那么改变后i+1也没法循环移动
                ori[i + 1] = 1;//i+1肯定不是原位置的啦
            }else if(c <= a && c <= b) {
                swap(s[i], s[i + 2]);
                swap(s[i + 1], s[i + 2]);
                //这时候其实i位是可能能保留了一次操作,先不要急着操作,后面再慢慢考虑。
                if(dwn[i]) dwn[i + 1] = 1;//但是如果原本i本来就没法循环移动,那么改变后i+1也没法循环移动
                ori[i + 1] = 1;//i+1肯定不是原位置的啦
                ori[i + 2] = dwn[i + 2] = 1;//原本i+1做了操作R,所以改变后肯定没法做循环移动操作,也不是原位置
            }
            // debug(i, s)
        }
        printf("%s
    ", s);
    }
    int main() {
    #ifdef LH_LOCAL
        freopen("D:/ACM/mtxt/in.txt", "r", stdin);
        // freopen("D:/ACM/mtxt/out.txt", "w", stdout);
    #endif
        for(int cas = 1, tim = read(); cas <= tim; ++ cas) {
            // printf("Case #%d:
    ", cas);
            work();
        }
    #ifdef LH_LOCAL
        cout << "time cost:" << 1.0 * clock() / CLOCKS_PER_SEC << "s" << endl;
    #endif
        return 0;
    }
    
  • 相关阅读:
    C# GDI+ 文字 阴影,描边 的实现
    NDatabase 入门,简单使用 增删改查。让NDatabase带你脱离ADO.net,各种SQL 语句,各种DBMS,各种CRM,IOC之类的烦恼。我们也不需要仓库设计模式了,你妹的。不要表了,不要设计数据库字段了。就这样!
    D3D 光和材质
    DirectX D3D texture 的Level,解释。。。。
    学习openssl中的hash算法
    ubuntu下使用魅族mx真机调试android程序
    boost 获取时间并格式化
    Mysql:The table‘xxxx’is full
    使用pmap查看进程占用的内存情况
    编译antrl c runtime 3.5步骤
  • 原文地址:https://www.cnblogs.com/Cwolf9/p/14121472.html
Copyright © 2020-2023  润新知