Codeforces Round #744 (Div. 3)

Codeforces Round #744 (Div. 3)

A. Casimir's String Solitaire

题目大意:给你一组只有A,B,C组成的字符串,按照如下的规则进行删除操作:每一次只能删除字母A和字母B,或者删除字母B和字母C,判断一个字符串能否被删除为空字符。

大致思路:扫描一边字符串统计出字母A,字母B,字母C的个数,如果字母A的个数加上字母B的个数等于字母C的个数该字符串即可删除为空。

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    cin.tie(0);
    int t;
    cin >> t;
    while (t--) {
        string str;
        cin >> str;
        int cnta = 0, cntb = 0, cntc = 0;
        for (auto s : str) {
            if (s == 'A') cnta++;
            if (s == 'B') cntb++;
            if (s == 'C') cntc++;
        }
        if (cnta + cntc == cntb) {
            cout << "YES" << endl;
            continue;
        }
        cout << "NO" << endl;
    }
    return 0;
}

B. Shifting Sort

题目大意:给你一个长度为n无序且数字不重复的数字,按照如下方式来操作数组:在数组中选择区间$$a[l...r]$$ 的数字,将该区间的数字想左旋转d个长度。经过最多n次旋转将数组旋转成为单调递增的数组,输出每一次选择的区间和旋转的长度。

大致思路:遍历数组中的每一个数字$$a[i]$$,然后找出该数字后面比这个数字小的最小的数字$$a[p]$$, 然后选择区间$$a[i...n]$$向左旋转 $$p - i$$个长度将数字$$a[p]$$旋转到$$a[i]$$的位置。因为每一次查找的是比数字$$a[i]$$最小的数字,所以我们可以保证在n次内就可以将数组排成升序。

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> a(n);
        for (int i = 0; i < n; ++i) cin >> a[i];
        vector<tuple<int, int, int>> ans;
        for (int i = 0; i < n; ++i) {
            int tmp = a[i];
            for (int j = i + 1; j < n; ++j) tmp = min(tmp, a[j]);
            int pos = -1;
            for (int k = i; k < n; ++k) {
                if (tmp == a[k]) {
                    pos = k;
                }
            }
            if (pos > i) {
                ans.push_back(make_tuple(i, n, pos - i));
                rotate(a.begin() + i, a.begin() + pos, a.end());
            }
        }
        cout << ans.size() << endl;
        for (int i = 0; i < ans.size(); ++i) {
            int l = get<0>(ans[i]) + 1;
            int r = get<1>(ans[i]);
            int d = get<2>(ans[i]);
            cout << l << " " << r << " " << d << endl;
        }
    }
    return 0;
}

C.Ticks

题目大意:给你一个n * m的网格,以网格$$(i, j)$$ 为中心,向左上角45度和右上角45度画直线,其中一个单元格的对角线的长度为一个单位,所画直线的单元格被标记,问你能够用长度至少为k的线将所有单元格都标记。

大致思路:因为题目要求的是由下到上开始画像,所以我们从下有上开始遍历所有还没有被染色的单元格$$(i,j)$$,以单元格$$(i,j)$$为中心查找左上角45度和右上角45度方位为“*”的最近的单元格。 然后判断所需直线的长度是否大于k

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, m, k;
        cin >> n >> m >> k;
        vector<vector<int>> maze(n, vector<int>(m, 1));
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                char ch;
                cin >> ch;
                if (ch == '*') maze[i][j] = 0;
            }
        }
        for (int i = n - 1; i >= 0; --i) {
            for (int j = 0; j < m; ++j) {
                if (maze[i][j] == 1) continue;
                int len = 0;
                while (i - len > 0 && j + len + 1 < m && j - len > 0) {
                    if (maze[i - len - 1][j + len + 1] == 1 ||
                        maze[i - len - 1][j - len - 1] == 1)
                        break;
                    ++len;
                }
                if (len >= k) {
                    for (int d = 0; d <= len; ++d) {
                        //被染色的点修改为另一个数字,防止下次判断的时候判断错误
                        maze[i - d][j + d] = 2;
                        maze[i - d][j - d] = 2;
                    }
                }
            }
        }
        bool flag = true;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (maze[i][j] == 0) {
                    flag = false;
                }
            }
        }
        if (flag)
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
    return 0;
}

D.Productive Meeting

题目大意:一组人去开会,为个人都有一个开会时间,开一次会会消耗一个单位时间,让尽可能多的开会输出每一次开会人的序号。

大致思路:尽可能多的开会,就安排开会时间少的人先在一起开会,利用优先队列处理即可。

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> a(n + 1);
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
        }
        priority_queue<pair<int, int>> pq;
        for (int i = 1; i <= n; ++i) {
            if (a[i] != 0) {
                //推入第i个人的社交值和编号
                pq.push(make_pair(a[i], i));
            }
        }
        vector<pair<int, int>> ans;
        while (pq.size() >= 2) {
            //优先让社交值小的两个人先交流这样可以让尽可能多的人交流
            int s1 = pq.top().first;
            int id1 = pq.top().second;
            pq.pop();
            int s2 = pq.top().first;
            int id2 = pq.top().second;
            pq.pop();
            ans.push_back(make_pair(id1, id2));
            if (s1 > 1) pq.push(make_pair(s1 - 1, id1));
            if (s2 > 1) pq.push(make_pair(s2 - 1, id2));
        }
        cout << ans.size() << endl;
        for (int i = 0; i < ans.size(); ++i) {
            cout << ans[i].first << " " << ans[i].second << endl;
        }
    }
    return 0;
}

E.Permutation Minimization by Deque

题目大意:给你一个数组,让你把这个数组按照如下规则重新排序:把小的数字尽可能放前面,大的数字尽可能放后面。

大致思路:用两个数字模拟即可,一个数组放小的数据,一个放大的。

代码:

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 2e5 + 10;
int a[MAXN], b[MAXN], c[MAXN];

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n;
        scanf("%d", &n);
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        memset(c, 0, sizeof(c));
        for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
        int cnt1 = n, cnt2 = 0;
        b[cnt1] = a[0];
        for (int i = 1; i < n; ++i) {
            if (a[i] > b[cnt1])
                c[cnt2++] = a[i];
            else
                b[--cnt1] = a[i];
        }
        for (int i = cnt1; i <= n; ++i) printf("%d ", b[i]);
        for (int i = 0; i < cnt2; ++i) printf("%d ", c[i]);
        printf("\n");
    }
    return 0;
}
上一篇:天梯赛L2-010 排座位


下一篇:Codeforces Round #744 (Div. 3) E2. Array Optimization by Deque (贪心,逆序对)