【cf比赛记录】Codeforces Round #604 (Div. 2)

比赛传送门

感觉这场是最近以来做过的最顺手的一场,持续上分,开心w

A了 前三题,然后第四题其实还有半个多小时,但怕身体撑不住,就先退了,其实第四题也很简单

自己认为的算法标签:

​ A.暴力模拟、字符串

​ B.数学、构造、排序

​ C.贪心、构造

​ D.构造、遍历

:D

A. Beautiful String

// https://codeforces.com/contest/1265/problem/A
/*
    要求:不能有连续相同的字符,然后把'?'改为'a' || 'b' || 'c',使最终字符串符合要求
        如果不满足就 '-1'

    -1 好办 ---- 如果原字符串里就不符合就为 -1
    我的做法是暴力模拟 ( 暴力的意思是代码有点长...然后自己 wa 了两发 tcl )
*/
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;

int T;
string a;
bool A, B, C;

int main()
{
    cin >> T;
    while(T--){
        cin >> a;
        A = B = C = false;

        bool ok = true; // 判断是否 -1
        int j = 0;

        for(int i = 1; i < a.size(); i++){
            if(a[i] == a[i - 1] && a[i] != '?'){
                ok = false; // 是 -1
                break;
            }
        }

        if(a.size() > 1 && ok){ // 长度超过 1 且 原字符串没有问题的情况
            // 特判第一位
            if(a[0] == '?'){
                if(a[1] == 'a') A = true;
                else if(a[1] == 'b') B = true;
                else if(a[1] == 'c') C = true;
                else if(a[1] == '?') a[0] = 'a';

                if(A) a[0] = 'b';
                else if(B) a[0] = 'c';
                else if(C) a[0] = 'a';
            }

            A = B = C = false;
            // 特判最后一位
            if(a[a.size() - 1] == '?'){
                if(a[a.size() - 2] == 'a') A = true;
                else if(a[a.size() - 2] == 'b') B = true;
                else if(a[a.size() - 2] == 'c') C = true;
                else if(a[a.size() - 2] == '?') a[a.size() - 1] = 'a';

                if(A) a[a.size() - 1] = 'b';
                else if(B) a[a.size() - 1] = 'c';
                else if(C) a[a.size() - 1] = 'a';
            }

            for(int i = 1; i < a.size() - 1; i++){ // 对 (1, size() - 1) 开始暴力搜索
                A = B = C = false; // 记录前后出现了哪个字符
                if(a[i - 1] == 'a') A = true;
                else if(a[i - 1] == 'b') B = true;
                else if(a[i - 1] == 'c') C = true;

                if(a[i + 1] == 'a') A = true;
                else if(a[i + 1] == 'b') B = true;
                else if(a[i + 1] == 'c') C = true;

                if(a[i] == '?'){ // 只需要改 '?'
                    if(A && B) a[i] = 'c';
                    else if(A && C) a[i] = 'b';
                    else if(B && C) a[i] = 'a';
                    else if(A) a[i] = 'b';
                    else if(B) a[i] = 'c';
                    else if(C) a[i] = 'a';
                }
            }
        }
        else if(a[0] == '?') a[0] = 'a'; // 字符串长度为 1 的情况 且是 "?"

        if(ok) cout << a << endl;
        else cout << -1 << endl;
    }
    return 0;
}

B.Beautiful Numbers

// https://codeforces.com/contest/1265/problem/B
/*
    题意是要找 在一个区间 [l, r] 的数据是否有序 (从 1 开始)
        结果是判断区间长度为 1 ~ n 是否满足要求

    既然是从 1 开始 如果满足条件 区间的长度必然等于区间数组里的[位置] 最大值 - 最小值 + 1
    根据这个结论就可以解决了

    样例一:
      排序前:
        数值  4 5 1 3 2 6
        位置  1 2 3 4 5 6

      排序后:
        数值  1 2 3 4 5 6
        位置  3 5 4 1 2 6

    区间长度为 3 时
        数值 [ 1 2 3 ] 4 5 6
        位置 [ 3 5 4 ] 1 2 6
        位置最大值 - 位置最小值 + 1 = 5 - 3 + 1 = 3 等于区间长度 3
    所以区间长度为 3 时可行
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
using namespace std;

struct node{
    int num, pla;
}mem[200005];
int T, n;

bool cmp(node a, node b){
    return a.num < b.num;
}

int main()
{
    scanf("%d", &T);
    while(T--){
        string ans;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++){
            scanf("%d", &mem[i].num);
            mem[i].pla = i; // 记录位置
        }
        sort(mem + 1, mem + 1 + n, cmp); // 把数据从 1 ~ n 升序排序

        int minn = n, maxx = 1;
        for(int i = 1; i <= n; i++){ // i 的大小等同于 区间的大小
//            printf("num:%d pla:%d\n", mem[i].num, mem[i].pla);
            // 更新当前区间里位置的最大最小值
            if(mem[i].pla < minn) minn = mem[i].pla;
            if(mem[i].pla > maxx) maxx = mem[i].pla;

            // 判断
            if(maxx - minn + 1 == i) ans += '1';
            else ans += '0';
        }

        cout << ans << endl; // 用 string 输出
    }

    return 0;
}

C.Beautiful Regional Contest

// https://codeforces.com/contest/1265/problem/C
/*
    贪心构造问题吧

    条件很多,但也很好利用
    1.获奖人数最多只有参赛人数的一半
    2.金牌的A题数 > 银牌的A题数 > 铜牌的A题数
    3.金牌的得奖数 < 银牌的, 铜牌的 (银牌与铜牌的多少没有要求)

    把 A 题最多的一组人授予金牌
    然后先依次给后面的人银牌,当银牌数比金牌数多时,剩下的都给铜牌 (这样容易避免铜牌数为 0 的情况)
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int T, n, cnt, a, x, y, z;
int mem[1000006];
int que[1000006];

bool cmp(int a, int b) { return a > b; }

int main()
{
    scanf("%d", &T);
    while(T--){
        // 初始化
        x = y = z = 0;
        for(int i = 0; i < cnt; i++){
            mem[que[i]] = 0;
        }
        cnt = 0;
        scanf("%d", &n);
        for(int i = 0; i < n; i++){
            scanf("%d", &a);
            if(mem[a] == 0){
                que[cnt++] = a; // 类似 set
            }
            mem[a]++;   // 桶排
        }

//        sort(que, que + cnt, cmp); // 因为题目就有降序输入,就不用 sort 了

        bool ok = true;

        int tot = n / 2; // 可以获奖的总人数 1
        x = mem[que[0]]; // 获得金牌的人数
        int last = tot - x; // 剩下银牌和铜牌最多的总数

        bool Z = false;
        for(int i = 1; i < cnt && last > 0; i++){
//            printf("x:%d y:%d z:%d last:%d\n", x, y, z, last);
            if(last < mem[que[i]]) break; // 当前组的人数比可给奖牌人数多时,就不能给了 (见样例 5)

            if(!Z){ // 开关 false 给银牌; true 给铜牌
                y += mem[que[i]];
                if(y > x){  // 银牌一旦符合了条件就给铜牌加
                    Z = true;
                }
            }
            else {
                z += mem[que[i]];
            }
            last -= mem[que[i]];
        }

        if(x >= y || x >= z) ok = false; // 判断是否符合条件
        if(ok) printf("%d %d %d\n", x, y, z);
        else printf("0 0 0\n");
    }
    return 0;
}

D.Beautiful Sequence

// https://codeforces.com/contest/1265/problem/D
/*
    感觉像是遍历的思维构造题 有思路就很好做的
    可以把该题想象成过山车或者山峰......
*/
#include<iostream>
#include<cstdio>
using namespace std;

int n;
int cnt[5], last[5]; // last 是记录当前还有多少 0, 1, 2, 3
int ans[100005];
bool ok;

int main()
{
    for(int i = 0; i < 4; i++) {
        scanf("%d", &cnt[i]);
        n += cnt[i]; // n 就是输出的总长度
    }

    for(int i = 0; i < 4; i++){
        if(!cnt[i]) continue;
        ans[1] = i; // 依次取 0, 1, 2, 3 为第一位开始
        ok = true;
        for(int j = 0; j < 4; j++){
            last[j] = cnt[j] - (i == j); // 初始化 last
        }

        for(int j = 2; j <= n; j++){ // 因为第一位已经放了所以从第二位开始
            int p = ans[j - 1];
            if(p - 1 >= 0 && last[p - 1]) { // 往小(低)处走
                ans[j] = p - 1; last[p - 1]--;
            }
            else if(p + 1 < 4 && last[p + 1]){ // 往大(高)处走
                ans[j] = p + 1; last[p + 1]--;
            }
            else ok = false; // 假如都不能 则当前做法不可取
        }
        if(ok){
            printf("YES\n");
            for(int i = 1; i <= n; i++){
                printf("%d%c", ans[i], i == n ? '\n' : ' ');
            }
            break;
        }
    }
    if(!ok) printf("NO\n");

    return 0;
}

记录菜鸟的成长:

猜你喜欢

转载自www.cnblogs.com/Ayanowww/p/11997319.html