Codeforces Round 941 (Div.1) & (Div. 2) A~E

2A. Card Exchange (思维)

题意:

你有 n n n张牌,每张牌上都写着一个数字,还有一个固定整数 k k k 。你可以多次进行下面的运算:

  • 从手牌中选择任意 k k k 张数字相同的牌。
  • 将这些牌换成 k − 1 k-1 k1 张牌,每张牌上可以换成任何数字。

在这个过程结束时,你手中最少有多少张牌?

分析:

如果存在某种数字的数量超过 k k k就可以一直进行操作,直到卡片数量为 k − 1 k-1 k1,否则不能替换。

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, k;
        cin >> n >> k;
        vector<int> a(n + 1, 0);
        map<int, int> mp;
        int flag = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            mp[a[i]]++;
            if (mp[a[i]] >= k)
                flag = 1;
        }
        if (flag)
            cout << k - 1 << endl;
        else
            cout << n << endl;
    }
    return 0;
}

2B.Rectangle Filling (思维)

题意:

有一个由白色和黑色方格组成的 n × m n \times m n×m 网格。在一次操作中,可以选择任意两个相同颜色的方格,并将它们之间的子方格中的所有方格都染成相同的颜色。
询问在进行任意次数可能为零的运算后,网格中所有网格的颜色是否可能相同?

分析:

只需要四条边缘上都有白色或者黑色色块,就可以使得所有网格的颜色相同。

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, m;
        cin >> n >> m;
        vector<string> s(n + 5);
        for (int i = 1; i <= n; i++)
            cin >> s[i];
        if (s[1][0] == s[n][m - 1] || s[1][m - 1] == s[n][0]) {
            cout << "YES" << endl;
            continue;
        }
        int flag1 = 0, flag2 = 0, flag3 = 0, flag4 = 0;
        for (int i = 0; i < m; i++)
            if (s[1][i] == 'W')
                flag1 = 1;
        for (int i = 0; i < m; i++)
            if (s[n][i] == 'W')
                flag2 = 1;
        for (int i = 1; i <= n; i++)
            if (s[i][0] == 'W')
                flag3 = 1;
        for (int i = 1; i <= n; i++)
            if (s[i][m - 1] == 'W')
                flag4 = 1;
        if (flag1 && flag2 && flag3 && flag4) {
            cout << "YES" << endl;
            continue;
        }
        flag1 = 0, flag2 = 0, flag3 = 0, flag4 = 0;
        for (int i = 0; i < m; i++)
            if (s[1][i] == 'B')
                flag1 = 1;
        for (int i = 0; i < m; i++)
            if (s[n][i] == 'B')
                flag2 = 1;
        for (int i = 1; i <= n; i++)
            if (s[i][0] == 'B')
                flag3 = 1;
        for (int i = 1; i <= n; i++)
            if (s[i][m - 1] == 'B')
                flag4 = 1;
        if (flag1 && flag2 && flag3 && flag4) {
            cout << "YES" << endl;
            continue;
        } else
            cout << "NO" << endl;
    }
    return 0;
}

2C1A.Everything Nim (博弈论)

题意:

爱丽丝和鲍勃正在玩一个关于 n n n 堆石子的游戏。轮到每个玩家时,他们都会选择一个正整数 k k k ,这个正整数最多等于最小的非空堆的大小,然后从每个非空堆中一次性取出 k k k 个石子。第一个没有石子可取的人输。
保证爱丽丝先下,并且如果双方都以最佳方式下棋,判断谁会赢。

分析:

假设最少的堆中只有一个石子,那么只能选择取一个,否则就可以自由决定取完最少堆或取到只剩一个来控制先后手。所以在我们轮流将只能取一个的堆取完后,谁先手则必胜,并且还需要额外考虑只能一直轮流取的情况。

代码:

#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];
        sort(a.begin() + 1, a.end());
        a.erase(unique(a.begin(), a.end()), a.end());
        int num = a.size() - 1;
        int tmp = -1;
        for (int i = 1; i <= num; i++)
            if (a[i] != i) {
                tmp = i;
                break;
            }
        if (tmp == -1) {
            if (num % 2)
                cout << "Alice" << endl;
            else
                cout << "Bob" << endl;
            continue;
        }
        if (tmp % 2 == 0)
            cout << "Bob" << endl;
        else
            cout << "Alice" << endl;
    }
    return 0;
}

2D1B.Missing Subsequence Sum (构造)

题意:

构造一个长度最大为 25 25 25的数组,使得数组的子序列和包含从 1 − n 1-n 1n除了 k k k以外所有数。

分析:

如果要去掉 k k k,那么需要找出 k k k二进制表示最大的那一位并将其去掉,再补齐其他数。设 k k k的最大位为 2 2 2 i i i次方,则加上 k − 2 i k-2^i k2i 就可以满足 1 1 1 k − 1 k-1 k1 的数,构造大于 k k k 的数需要加上 k + 1 k+1 k+1,后面构造的数字都可以在加上 k + 1 k+1 k+1的基础上构造,于是再添加 2 i + k + 1 2^i + k +1 2i+k+1 k + 1 k+1 k+1 的差就可以实现剩下的数字。

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, k;
        vector<int> ans;
        cin >> n >> k;
        int i = 1, rest = 0;
        while (1) {
            if (k == 1)
                break;
            if (rest + i + 1 >= k) {
                ans.push_back(k - rest - 1);
                break;
            } else {
                ans.push_back(i);
                rest += i;
            }
            i <<= 1;
        }
        ans.push_back(k + 1), ans.push_back(k * 2 + 1);
        int tmp = k * 3;
        for (int i = k * 2; tmp < n; i <<= 1)
            ans.push_back(tmp - k), tmp += i;
        cout << ans.size() << endl;
        for (auto v: ans) {
            cout << v << " ";
        }
        cout << endl;
    }
    return 0;
}

2E1C. Folding Strip (思维)

题意:

有一张纸条,上面是长度为 n n n 的二进制字符串 s s s 。现在可以将纸条折叠在任意一对相邻数字之间。
如果在折叠后,位于上方或下方的所有字符都匹配,则认为一组折叠有效。请注意,所有折叠都是同时进行的,因此折叠之间的字符不必匹配。
在完成一组有效的折叠后,能形成的最小长度条带是多少?

分析:

考虑到折叠后的纸条必然是交替的串,那么相邻位置如果相同的话一定会被折叠。那么就是先顺着一个方向折叠,遇到相同的数字就转向,记录一下往左往右能折叠到最远的地方,这个距离就是答案。

代码:

#include <bits/stdc++.h>

using namespace std;
const int N = 1e6 + 5;
const int mod = 998244353;
int a[N];

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        string tmp;
        cin >> tmp;
        for (int i = 0; i < n; i++) {
            a[i + 1] = tmp[i] - '0';
        }
        int l = 1, r = 1, now = 1, w = 1;
        a[0] = -1;
        for (int i = 1; i <= n; i++) {
            if (a[i] == a[i - 1])
                w *= -1;
            now += w;
            l = min(l, now);
            r = max(r, now);
        }
        cout << r - l << endl;
    }
    return 0;
}

赛后交流

在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。

群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值