Codeforces Round #612 (Div. 2)

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

A - Angry Students

题意

有一字符串由 'A','P' 组成,每分钟 'A' 可以使右边相邻的 'P' 变为 'A',问字符串稳定下来需要多少分钟。

题解

查找每个 'A' 后的最长连续 'P' 串。

代码

#include <bits/stdc++.h>
using namespace std;

void solve() {
    int k; string s; cin >> k >> s;
    int ans = 0;
    for (int i = 0; i < k; i++) {
        if (s[i] == 'A') {
            ++i;
            int cnt = 0;
            while (i < k and s[i] == 'P') ++cnt, ++i;
            ans = max(ans, cnt);
            --i;
        }
    }
    cout << ans << "\n";
}

int main() {
    int t; cin >> t;
    while (t--) solve();
}

B - Hyperset

题意

有 n 个长为 k ,由 'S', 'E', 'T' 组成的字符串,若三个字符串同一位置的字符全部相同或两两不同,我们称之为一个三元组,试找出 n 个字符串中三元组的个数(不考虑三个字符串的前后顺序)。(1≤n≤1500,1≤k≤30)

题解

若枚举三个字符串的情况则复杂度高达 $O_{(n^3k)}$,显然是不现实的,注意到,当前两个字符串确定后第三个字符串也已经确定了,所以可以记录每个字符串的个数,枚举前两个字符串的情况然后查询第三个字符串的个数,当然这样同一个三元组会计入三次,所以最后的结果需要再除以三。这样就可以在 $O_{(n^2k)}$ 的时间复杂度内解决该问题。

代码

#include <bits/stdc++.h>
using LL = long long;
using namespace std;

int main() {
    int n, k; cin >> n >> k;
    map<string, LL> mp;
    string s[n];
    for (auto &i : s) cin >> i, mp[i]++;
    LL ans = 0;
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            string des(k, '0');
            for (int _ = 0; _ < k; _++) {
                if (s[i][_] == s[j][_]) des[_] = s[i][_];
                else for (char c : {'S', 'E', 'T'}) {
                        if (c != s[i][_] and c != s[j][_])
                            des[_] = c;
            }
            ans += mp[des];
        }
    }
    cout << ans / 3 << "\n";
}

C - Garland

题意

有一个残缺的排列,空位置为 0,求补全后奇偶相邻的最少对数。

题解

dp[i][j][0] 表示当前第 i 个位置为偶数,位置 [1, i] 中共有 j 个偶数。

dp[i][j][1] 表示当前第 i 个位置为奇数,位置 [1, i] 中共有 j 个偶数。

代码

#include <bits/stdc++.h>
using namespace std;

const int M = 110;
int a[M], dp[M][M][2];

int main() {
    int n; cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    memset(dp, M, sizeof dp);
    dp[0][0][0] = dp[0][0][1] = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= i; j++) {
            if (a[i] == 0) {
                dp[i][j][0] = min(dp[i - 1][j - 1][0], dp[i - 1][j - 1][1] + 1);
                dp[i][j][1] = min(dp[i - 1][j][1], dp[i - 1][j][0] + 1);
            } else {
                if (a[i] % 2 == 0) dp[i][j][0] = min(dp[i - 1][j - 1][0], dp[i - 1][j - 1][1] + 1);
                if (a[i] % 2 == 1) dp[i][j][1] = min(dp[i - 1][j][1], dp[i - 1][j][0] + 1);
            }
        }
    }
    cout << min(dp[n][n / 2][0], dp[n][n / 2][1]);
}

D - Numbers on Tree

题意

给一棵树的结点赋值,要求每棵子树中值小于根节点 i 的结点个数为 ci

题解

从最深的子节点开始构造,依次把每个结点插入当前第 ci 大的位置。

代码

#include <bits/stdc++.h>
using namespace std;

const int M = 2200;
int c[M], ans[M];
vector<int> e[M], v;

int dfs(int u) {
    int sz = 1;
    for (int v : e[u]) sz += dfs(v);
    if (u != 0) {
        if (c[u] >= sz) { cout << "NO" << "\n"; exit(0); }
        v.insert(v.begin() + c[u], u);
    }
    return sz;
}

int main() {
    int n; cin >> n;
    for (int i = 1; i <= n; i++) {
        int u; cin >> u >> c[i];
        e[u].push_back(i);
    }
    dfs(0);
    for (int i = 0; i < v.size(); i++) ans[v[i]] = i + 1;
    cout << "YES" << "\n";
    for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
}

 

posted @ 2020-04-28 21:00  Kanoon  阅读(126)  评论(0)    收藏  举报