1. 程式人生 > 其它 >Codeforces Round #744 (Div. 3)

Codeforces Round #744 (Div. 3)

Codeforces Round #744 (Div. 3)A~E1題解

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;
}