Educational Codeforces Round 123 (Rated for Div. 2) (A-D题解)

Educational Codeforces Round 123 (Rated for Div. 2) (A-D题解)

源代码:ACM/OpenjudgeNow/Codeforces at master · abmcar/ACM (github.com)

更好的阅读体验: 折跃坐标

A. Doors and Keys

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

把当前得到的钥匙数存起来判断即可,可以使用isupper()和map简化

代码:

void solution()
{
    cin >> oriS;
    M.clear();
    for (char it : oriS)
    {
        M[it]++;
        if (isupper(it))
        {
            if (M[it] > M[it + 32])
            {
                cout << "NO" << endl;
                return;
            }
        }
    }
    cout << "YES" << endl;
}

B. Anti-Fibonacci Permutation

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

不难发现该排列很容易生成,当前面为1 3 2 时,后面的很容易得到所需排列

再swap第2,3个数后,使用next_permutation可以生成下一个排列

代码:

void solution()
{
    cin >> n;
    int cnt = 0;
    vector<int> V(n);
    for (int i = 0; i < n; i++)
        V[i] = i + 1;
    swap(V[1], V[2]);
    while (next_permutation(V.begin(), V.end()) && cnt < n)
    {
        bool ok = true;
        for (int i = 2; i < n; i++)
            if (V[i - 1] + V[i - 2] == V[i])
            {
                ok = false;
                break;
            }
        if (ok)
        {
            cnt++;
            for (int it : V)
                cout << it << " ";
            cout << endl;
        }
    }
}

C. Increase Subarray Sums

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

发现n只有5000,且题目需要的是连续子序列,因此我们可以做一遍前缀和,之后枚举区间,得到相同长度和最大的连续子序列

之后对于每一个k,枚举所有区间长度,加上min(k,size)*x后得到的最大值即为结果

代码:

void solution()
{
    cin >> n >> m;
    vector<int> nums(n + 1), preAns(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> nums[i];
    for (int i = 1; i <= n; i++)
        preAns[i] = preAns[i - 1] + nums[i];
    vector<int> M(n + 1, -1e18);
    vector<pair<int, int>> allSem;
    for (int len = 1; len <= n; len++)
    {
        for (int str = 1; str + len - 1 <= n; str++)
        {
            M[len] = max(M[len], preAns[str + len - 1] - preAns[str - 1]);
        }
        allSem.push_back({M[len], len});
    }
    for (int len = 0; len <= n; len++)
    {
        int nowAns = 0;
        for (auto it : allSem)
            nowAns = max(nowAns, it.first + m * min(len, it.second));
        cout << nowAns << " \n"[len == n];
    }
}

D. Cross Coloring

在这里插入图片描述

题目大意:

在这里插入图片描述

思路:

由于在后面涂的色会覆盖之前图的色,因此需要逆序处理

每涂一行/一列,把相应的行,列标记上

如果之前涂的色再行/列上会被后来的操作覆盖,则跳过

同理,如果所有行/列被覆盖,则跳过

代码:

void solution()
{
    cin >> n >> m;
    vector<int> nums(n + 1), preAns(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> nums[i];
    for (int i = 1; i <= n; i++)
        preAns[i] = preAns[i - 1] + nums[i];
    vector<int> M(n + 1, -1e18);
    vector<pair<int, int>> allSem;
    for (int len = 1; len <= n; len++)
    {
        for (int str = 1; str + len - 1 <= n; str++)
        {
            M[len] = max(M[len], preAns[str + len - 1] - preAns[str - 1]);
        }
        allSem.push_back({M[len], len});
    }
    for (int len = 0; len <= n; len++)
    {
        int nowAns = 0;
        for (auto it : allSem)
            nowAns = max(nowAns, it.first + m * min(len, it.second));
        cout << nowAns << " \n"[len == n];
    }
}