Codeforces Round 884 (Div. 1 + Div. 2) A-E

发布时间 2023-07-14 16:42:27作者: FlyingLight

Codeforces Round 884 (Div. 1 + Div. 2)

题目链接:Codeforces Round 884 (Div. 1 + Div. 2)

A. Subtraction Game

题意

\(a\)\(b\)两个数,两个玩家每次可以选择在总数里面减去其中一个数,需要给出一种后手必胜的总数\(n\)

思路

\(a+b\)就能保证后手必胜。

代码

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

void sol() {
    int x, y;
    cin >> x >> y;
    cout << x + y << endl;
}

int main() {
    int _;
    cin >> _;
    while (_--) sol();
    return 0;
}

B. Permutations & Primes

题意

定义一个序列的\(MEX\)为这个序列中没有出现的第一个质数,让求能让所有连续子序列的\(MEX\)的和最大的那个排列。

思路

首先,\(1\)肯定在最中间的位置,因为需要尽可能多的子序列都包含他。由于2和3都是质数,所以两边各一个就行,这样只有\([1,n]\)的区间才会同时包含\(2和3\),这就意味着,除了这三个数,其他数的排列顺序不会影响结果。

代码

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

void sol() {
    int n;
    cin >> n;
    if (n >= 2) cout << 2;
    for (int i = 4; i <= n / 2 + 2; ++i) cout << ' ' << i;
    cout << (n > 1 ? " 1" : "1");
    for (int i = n / 2 + 3; i <= n; ++i) cout << ' ' << i;
    if (n >= 3) cout << ' ' << 3;
    cout << endl;
}
int main() {
    int _;
    cin >> _;
    while (_--) sol();
    return 0;
}

C. Particles

题意

给出\(n\)个数,每次可以删除一个数,然后相邻的两个数会求和合并成一个数,删除两端的数时,不会有合并操作,问最后合成一个数后最大的结果。

思路

首先,很容易注意到一件事,奇数下标的数只能跟奇数下标的数和到一块,偶数也一样,这意味着我们可以把原数组按下标的奇偶性分成两个数组考虑。又由于下标奇偶性相同的两个数总能够通过若干次操作合到一块,所以实际上就是让求两个数组中所有正数的和,大的那个就是结果。如果两个数组中都没正数,说明最大的那个负数就是结果。

代码

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 1e5 + 5, maxnn = 1e9 + 7;

int a[maxn], b[maxn];

void sol() {
    int n, g1 = 0, g2 = 0;
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> (i & 1 ? a[++g1] : b[++g2]);
    int ma = -maxnn;
    LL sum1 = 0, sum2 = 0, ans = -maxnn;
    for (int i = 1; i <= g1; ++i) {
        if (a[i] > 0) sum1 += a[i], ans = max(ans, sum1);
        ma = max(ma, a[i]);
    }
    for (int i = 1; i <= g2; ++i) {
        if (b[i] > 0) sum2 += b[i], ans = max(ans, sum2);
        ma = max(ma, b[i]);
    }
    if (ma <= 0)
        cout << ma << endl;
    else
        cout << ans << endl;
}

int main() {
    int _;
    cin >> _;
    while (_--) sol();
    return 0;
}

D. Row Major

题意

给一个\(n\),要求构造一个字符串,使得对于任何满足式子\(n=a×b\)\(a和b\),按“行优先”规则写成\(a×b\)的形式后,任意相邻的两个字符不能相同,问最少需要的字符种类数\(x\)

思路

考虑到一个事实:对于任意的\(a×b\)矩阵,只要\(x\)不整除\(a或b\),那么就有一定的排列方式使得相邻的字符都互不相同。我们在这里可以缩紧条件,让\(x\)必须整除\(a\),这样问题就转化为了:对于所有\(n\)的因子\(y_i\),需要求最小的\(x\),使得\(x\)不整除任何一个\(y_i\),也就是求最小的不整除\(n\)\(x\)。又由于\(26!\)远远大于\(1e6\),所以对于所有的\(n\)\(x\)肯定是小于等于\(26\)的(其实从小写字母一共就\(26\)个也能看出来...)。

代码

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

void sol() {
    int n, ans;
    cin >> n;
    ans = n;
    for (int i = 1; i <= 26; ++i) {
        if (n % i != 0) {
            ans = i;
            break;
        } 
    }
    for (int i = 1; i <= n; ++i) cout << (char)('a' + (i - 1) % ans);
    cout << endl;
}

int main() {
    int _;
    cin >> _;
    while (_--) sol();
    return 0;
}

E. Great Grids

题意

对于一个只含有三种字符的矩阵,如果他的每个\(2×2\)的小矩阵都存在三种不同的字符且相邻的字符不相同,那么就称其为\(great\)。给出\(k\)个限制,每个限制都是两个点的坐标,意味着这两个点的字符相同,且满足

\((x_{i,2},y_{i,2})=(x_{i,1}+1,y_{i,1}+1)或者(x_{i,2},y_{i,2})=(x_{i,1}+1,y_{i,1}−1)\)。问是否存在\(n×m\)\(great\)矩阵满足上述条件。

思路

对于\(great\)矩阵的每个\(2×2\)的小矩阵,例如:

AB     BA
CA     AC

可以发现以下事实:

\(a[i+1][j]-a[i][j]=a[i+1][j+1]-a[i][j+1]\)以及\(a[i][j+1]-a[i][j]=a[i+1][j+1]-a[i+1][j]\)。并且\(a[i+1][j]-a[i][j]\)\(a[i][j+1]-a[i][j]\)的值在模\(3\)的意义下,只能为\(1或者2\)

所以对\(n×m\)的矩阵可以把前\(n-1\)个行和前\(m-1个列\),看作\(n+m-2\)个点,又由于题目上的每一个限制,是对一个行和一个列对应的值相同或不同的限制,那么每个限制实际上是对两个点是否在同一个集合进行的限制。这样,这个题就转化为了一个二分图判定的题,这里可以使用并查集来快速判定。

代码

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

const int maxn = 2e3 + 5;

int r[maxn][2], c[maxn][2], f[4 * maxn];

int find(int x) {
    if (f[x] == x) return x;
    return f[x] = find(f[x]);
}

void merge(int x, int y) { f[find(x)] = find(y); }

void sol() {
    int n, m, k;
    cin >> n >> m >> k;
    int tmp = 0;
    for (int i = 1; i <= n; ++i) r[i][0] = tmp++, r[i][1] = tmp++;
    for (int i = 1; i <= m; ++i) c[i][0] = tmp++, c[i][1] = tmp++;
    for (int i = 0; i < tmp; ++i) f[i] = i;
    for (int i = 1; i <= k; ++i) {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        if (y1 > y2) {
            merge(r[x1][0], c[y2][0]);
            merge(r[x1][1], c[y2][1]);
        } else {
            merge(r[x1][0], c[y1][1]);
            merge(r[x1][1], c[y1][0]);
        }
    }
    for (int i = 0; i < tmp; ++i)
        if (find(i) == find(i ^ 1)) {
            cout << "NO" << endl;
            return;
        }
    cout << "YES" << endl;
}

int main() {
    int _;
    cin >> _;
    while (_--) sol();
    return 0;
}