Educational Codeforces Round 105 (Rated for Div. 2)【ABC】

好久不见~ 这里是某鸽子博主的突然更新 (ෆ´ ˘ `ෆ)♡

比赛链接:https://codeforces.com/contest/1494

A. ABC String

题解

字符串首端的字母一定是用 '(' 代替,末端的字母一定是用 ')' 代替,第三类字符枚举 '(' , ')' 两种情况即可。

代码

#include <bits/stdc++.h>
using namespace std;
bool check(const string& s) {
    int l = 0;
    for (char c : s) {
        if (c == '(') {
            ++l;
        } else {
            --l;
        }
        if (l < 0) {
            return false;
        }
    }
    return l == 0;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        string s;
        cin >> s;
        bool ok = false;
        for (char rep_c : {'(', ')'}) {
            string t(s);
            for (char& c : t) {
                if (c == s.front()) {
                    c = '(';
                } else if (c == s.back()) {
                    c = ')';
                } else {
                    c = rep_c;
                }
            }
            ok or_eq check(t);
        }
        cout << (ok ? "YES" : "NO") << "
";
    }
    return 0;
}

B. Berland Crossword

题解

枚举四个角的摆放状态即可,可以用状压,也可以用dfs。

代码

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int n, up, rt, dw, lf;
        cin >> n >> up >> rt >> dw >> lf;
        bool ok = false;
        for (int i = 0; i < (1 << 4); i++) {
            int u = up, r = rt, d = dw, l = lf;
            if (i >> 3 & 1) {
                --l, --u;
            }
            if (i >> 2 & 1) {
                --r, --u;
            }
            if (i >> 1 & 1) {
                --l, --d;
            }
            if (i >> 0 & 1) {
                --r, --d;
            }
            if (min({u, r, d, l}) >= 0 and max({u, r, d, l}) <= n - 2) {
                ok = true;
            }
        }
        cout << (ok ? "YES" : "NO") << "
";
    }
    return 0;
}

C. 1D Sokoban

题解

以正数的情况为例,每次枚举当前特殊点为推箱子的终点,二分查找前面有多少个箱子及特殊点,当前特殊点之后与箱子重合的特殊点个数可以预处理。

负数取绝对值反转后与正数情况相同。

代码

#include <bits/stdc++.h>
using namespace std;
int cal (const auto& a, const auto& b) {
    int m = b.size();
    vector<int> dp(m); //当前特殊点及右侧有多少与箱子位置重合
    for (int i = m - 1; i >= 0; i--) {
        if (binary_search(a.begin(), a.end(), b[i])) {
            dp[i] = 1;
        }
        if (i + 1 < m) {
            dp[i] += dp[i + 1];
        }
    }
    int res = 0;
    for (int i = 0; i < m; i++) { //枚举特殊点为推箱子的终点
        int num = upper_bound(a.begin(), a.end(), b[i]) - lower_bound(a.begin(), a.end(), 0); //当前特殊点及左侧有多少个箱子
        int l = b[i] - (num - 1); //第一个箱子的位置
        int r = b[i]; //最后一个箱子的位置
        int in_seg = upper_bound(b.begin(), b.end(), r) - lower_bound(b.begin(), b.end(), l); //箱子间有多少个特殊点
        int idx = upper_bound(b.begin(), b.end(), r) - b.begin(); //最后一个箱子位置右侧的特殊点的下标
        res = max(res, min(num, in_seg) + (0 <= idx and idx < m ? dp[idx] : 0));
    }
    return res;
};
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int n, m;
        cin >> n >> m;
        vector<int> pos_a, neg_a;
        for (int i = 0; i < n; i++) {
            int x;
            cin >> x;
            if (x > 0) {
                pos_a.push_back(x);
            } else {
                neg_a.push_back(-x);
            }
        }
        vector<int> pos_b, neg_b;
        for (int i = 0; i < m; i++) {
            int x;
            cin >> x;
            if (x > 0) {
                pos_b.push_back(x);
            } else {
                neg_b.push_back(-x);
            }
        }
        reverse(neg_a.begin(), neg_a.end());
        reverse(neg_b.begin(), neg_b.end());
        cout << cal(pos_a, pos_b) + cal(neg_a, neg_b) << "
";
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Kanoon/p/14476642.html