Codeforces Round 929(Div.3) A~G

A.Turtle Puzzle: Rearrange and Negate (思维)

题意:

给出一个长度为 n n n的数组 a a a,可以选择进行以下两种操作:

  • 将数组随机打乱
  • 选择一段区间并取反

询问经过操作之后,数组和最大是多少。

分析:

通过操作可以将所有负数集中到一个区间,然后再进行翻转,所以数组和最大就是所有元素绝对值相加。

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            int x;
            cin >> x;
            sum += abs(x);
        }
        cout << sum << endl;
    }
    return 0;
}

B.Turtle Math: Fast Three Task (模拟)

题意:

给定一个长度为 n n n的数组 a a a,你可以进行以下两种操作:

  • 删除数组中的一个元素
  • 选择其中一个元素,将它的值加 1 1 1

你可以执行任意次上述操作,询问至少需要多少次操作可以使得最终数组总和能被 3 3 3整除。

分析:

分情况讨论:

  • 本身被 3 3 3整除,无需操作

  • 3 3 3 1 1 1,查找是否有元素模 3 3 3 1 1 1,如果有就删除

  • 3 3 3 2 2 2,任选一个元素加 1 1 1

  • 其他情况都需要两次操作。

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        int sum = 0;
        int flag = 0;
        for (int i = 1; i <= n; i++) {
            int x;
            cin >> x;
            if (x % 3 == 1)
                flag = 1;
            sum += x;
        }
        sum %= 3;
        if (sum) {
            if ((sum == 1 && flag) || (sum == 2)) {
                sum = 1;
            } else {
                sum = 2;
            }
        }
        cout << sum << endl;
    }
    return 0;
}

C. Turtle Fingers: Count the Values of k (数学)

题意:

询问存在多少种非负整数 k k k,使得在 k , x , y k,x,y k,x,y都是非负数的情况,满足下列等式:

  • l = k × a x × b y l=k \times a^x \times b^y l=k×ax×by

分析:

直接枚举 x , y x,y x,y,并用 s e t set set k k k去重。

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;

int main() {
    int t;
    cin >> t;
    while (t--) {
        LL a, b, l;
        cin >> a >> b >> l;
        vector<LL> x, y;
        LL s = 1;
        while (s <= l) {
            x.push_back(s);
            s *= a;
        }
        s = 1;
        while (s <= l) {
            y.push_back(s);
            s *= b;
        }
        set<LL> tmp;
        for (auto v: x) {
            for (auto u: y) {
                if (l % (v * u) == 0) {
                    tmp.insert(v * u);
                }
            }
        }
        cout << tmp.size() << endl;
    }
    return 0;
}

D.Turtle Tenacity: Continual Mods (思维)

题意:

给一个长度为 n n n的数组 a a a,询问能否将其打乱得到一个新数组 b b b,并满足以下条件:

  • b 1 % b 2 % b 3 … b n ≠ 0 b_1 \% b_2 \% b_3 \dots b_n \neq 0 b1%b2%b3bn=0

分析:

对每个 a i a_i ai除以 a a a数组的 g c d gcd gcd,如果数组中的最小值只有 1 1 1个,那么从最小值开始取模可以满足情况。如果最小值有多个,我们要尝试通过取模操作得到一个比当前最小值更小的数字,如果当前最小值是 1 1 1,比最小值更小的值是 0 0 0,输出NO。如果最小值大于 1 1 1,数组中一定存在一个比它大的数字,用它对最小值取模就可以得到一个更小的数字。

代码:

#include <bits/stdc++.h>

using namespace std;

int a[100005];

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        for (int i = 0; i < n; i++) cin >> a[i];
        int gcd = a[0];
        for (int i = 1; i < n; i++) gcd = __gcd(gcd, a[i]);
        for (int i = 0; i < n; i++) a[i] /= gcd;
        sort(a, a + n);
        if (a[0] != a[1]) {
            cout << "YES" << endl;
        } else if (a[0] != 1) {
            cout << "YES" << endl;
        } else cout << "NO" << endl;
    }
    return 0;
}

E.Turtle vs. Rabbit Race: Optimal Trainings (二分)

题意:

A A A n n n 条跑道可供使用, i i i 条跑道由 a i a_i ai 个等长的部分组成。
给定一个整数 u u u,完成每一段都能使小 A A A的能力提高一个特定值,具体描述如下:

  • 完成 1 1 1 1 1 1-st)部分会使小 A A A的成绩提高 u u u
  • 完成 2 2 2(nd)部分会使小 A A A的能力提高 u − 1 u-1 u1
  • 完成 3 3 3-rd 部分会使小 A A A的成绩提高 u − 2 u-2 u2
  • … \ldots
  • 完成 k k k-th 部分( k ≥ 1 k \ge 1 k1 )会使小 A A A的成绩提高 u + 1 − k u+1-k u+1k u + 1 − k u+1-k u+1k 的值可以是负数,这意味着完成额外的部分会降低小 A A A的成绩。

给出一个整数 l l l 。询问选择一个整数 r r r ,使 l ≤ r ≤ n l \le r \le n lrn 和小 A A A都能完成赛道 l , l + 1 , … , r l, l + 1, \dots, r l,l+1,,r 的段。(即总共完成 ∑ i = l r a i = a l + a l + 1 + … + a r \sum\limits_{i=l}^r a_i = a_l + a_{l+1} + \ldots + a_r i=lrai=al+al+1++ar 节)。
询问所能选择的最佳 r r r ,使得小 A A A的成绩最大。如果有相同的 r r r输出最小的。

分析:

计算前缀和,二分查找第一个 s [ r ] − s [ l − 1 ] > u s[r]-s[l-1]>u s[r]s[l1]>u的位置 r 1 r1 r1,以及最后一个 s [ r ] − s [ l − 1 ] ≤ u s[r]-s[l-1] \le u s[r]s[l1]u的位置 r r r。利用等差数列求和,并将 r 1 , r 2 r1,r2 r1,r2的结果取最大值。

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
int a[N], sum[N];

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, q;
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            sum[i] = sum[i - 1] + a[i];
        }
        cin >> q;
        while (q--) {
            int l, u;
            cin >> l >> u;
            auto solve = [&](int x) -> LL {
                int c = sum[x] - sum[l - 1];
                LL res = 1LL * (2 * u + 1 - c) * c / 2;
                return res;
            };
            if (sum[l - 1] + u >= sum[n]) {
                cout << n << " ";
                continue;
            }
            if (sum[l - 1] + u < sum[l]) {
                cout << l << " ";
                continue;
            }
            int r1 = upper_bound(sum + 1, sum + n + 1, sum[l - 1] + u) - sum;
            int r2 = upper_bound(sum + 1, sum + n + 1, sum[l - 1] + u) - sum - 1;
            if (solve(r1) > solve(r2))
                cout << r1 << " ";
            else
                cout << r2 << " ";
        }
        cout << endl;
    }
    return 0;
}

F.Turtle Mission: Robot and the Earthquake (bfs)

题意:

有一个 n n n 行和 m m m 列的网格。单元格状态用 a i a_i ai表示:

  • 如果是 a i , j = 1 a_{i,j} = 1 ai,j=1 ,则 ( i , j ) (i,j) (i,j) 处有一块石头。
  • 如果是 a i , j = 0 a_{i,j} = 0 ai,j=0 ,则 ( i , j ) (i,j) (i,j) 处什么都没有。

由于地震余震的影响,石头跟随构造板块运动:每个石头以每单位时间 1 1 1 个单元的速度循环向上移动。从形式上看,如果 ( i , j ) (i,j) (i,j) 中包含一块岩石,那么它将从 ( i , j ) (i, j) (i,j) 移动到 ( i − 1 , j ) (i - 1, j) (i1,j) (如果 ( i − 1 , j ) (i - 1, j) (i1,j) 中包含一块岩石,那么它将从 ( i , j ) (i, j) (i,j) 移动到 ( n − 1 , j ) (n - 1, j) (n1,j) )。
名为 R T RT RT 的机器人最初位于 ( 0 , 0 ) (0,0) (0,0) 。它必须移动到 ( n − 1 , m − 1 ) (n-1,m-1) (n1,m1) 处进行地震救援(移动到最右下方的单元格)。地震不会改变机器人的位置,只会改变世界中岩石的位置。
假设 R T RT RT 的当前位置为 ( x , y ) (x,y) (x,y),它可以进行以下操作:

  • 循环向上移动一格,即使用 1 1 1 单位时间从 ( x , y ) (x,y) (x,y) 移动到 ( ( x + n − 1 )   m o d   n , y ) ((x+n-1) \bmod n, y) ((x+n1)modn,y)
  • 向下循环移动一个单元格,即以 1 1 1 为时间单位从 ( x , y ) (x,y) (x,y) 移动到 ( ( x + 1 )   m o d   n , y ) ((x+1) \bmod n, y) ((x+1)modn,y)
  • 向右移动一格,即使用 1 1 1 个时间单位从 ( x , y ) (x,y) (x,y) ( x , y + 1 ) (x, y+1) (x,y+1) 。(只有在 y ≤ m − 1 y \le m-1 ym1 时, R T RT RT 才能执行此操作)。

注意, R T RT RT 不能使用操作向左移动,也不能停留在某一位置。
R T RT RT 到达 ( n − 1 , m − 1 ) (n-1,m-1) (n1,m1) 时不与任何岩石相撞所需的最短时间。如果无法做到,输出 − 1 -1 1

分析:

将每次的移动当做表格中的障碍物没有移动,机器人的移动变成:原地不动,向下两步,向右下一步。由于终点也会发生变化,所以先到达最后一列然后再移动到终点的位置最优,先使用 B F S BFS BFS计算到达最后一列的最小步数,然后计算最后一列的点与终点的最小距离。

代码:

#include <bits/stdc++.h>

using namespace std;
#define PII pair<int, int>
const int N = 1e3 + 10;
int a[N][N], dist[N][N];
int dir[2][2] = {{2, 0}, {1, 1}};

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, m;
        cin >> n >> m;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                cin >> a[i][j];
                dist[i][j] = 0;
            }
        }
        int end = n - 1;
        int ex, ey;
        bool flag = 0;
        queue<PII > q;
        q.push({0, 0});
        while (q.size()) {
            int cnt = q.size();
            while (cnt--) {
                int x = q.front().first;
                int y = q.front().second;
                q.pop();
                if (y == m - 1) {
                    ex = x;
                    ey = y;
                    flag = true;
                    break;
                }
                for (int i = 0; i < 2; i++) {
                    int nx = x + dir[i][0];
                    int ny = y + dir[i][1];
                    nx = nx % n;
                    if (nx < 0 || nx >= n || ny < 0 || ny >= m)
                        continue;
                    if (i == 0 && (a[(x + 1) % n][y] == 1 || a[(x + 2) % n][y] == 1))
                        continue;
                    if (i == 1 && (a[(x + 1) % n][y + 1] == 1))
                        continue;
                    if (dist[nx][ny])
                        continue;
                    q.push({nx, ny});
                    dist[nx][ny] = dist[x][y] + 1;
                }
            }
            if (flag)
                break;
            end++;
        }
        if (flag == 0) {
            cout << -1 << endl;
        } else {
            end = end % n;
            cout << dist[ex][ey] + min(abs(end - ex), (n - abs(end - ex)) % n) << endl;
        }
    }
    return 0;
}

G.Turtle Magic: Royal Turtle Shell Pattern (打表)

题意:

给一个 n × m n \times m n×m的网格,最初,整个网格是空的。进行 q q q 次操作。 i i i次操作如下:指定当前空单元格 ( r i , c i ) (r_i,c_i) (ri,ci) 和一个形状(圆形或方形),然后在单元格 ( r i , c i ) (r_i,c_i) (ri,ci) 中放入一个指定形状的幸运饼干。在进行 i i i 操作后,单元格 ( r i , c i ) (r_i,c_i) (ri,ci) 不再为空。

在每次操作之前,以及所有操作结束之后,询问在所有剩余的空单元格中放置幸运饼干的方法有多少种,从而满足以下条件:

没有三个连续的单元格(水平方向、垂直方向和对角线方向)包含相同形状的饼干。形式上

  • 不存在满足 1 ≤ i ≤ n , 1 ≤ j ≤ m − 2 1 \le i \le n, 1 \le j \le m-2 1in,1jm2 条件的 ( i , j ) (i,j) (i,j) ,即 ( i , j ) , ( i , j + 1 ) , ( i , j + 2 ) (i,j), (i,j+1), (i,j+2) (i,j),(i,j+1),(i,j+2) 单元格中有相同形状的饼干。
  • 不存在满足 1 ≤ i ≤ n − 2 , 1 ≤ j ≤ m 1 \le i \le n-2, 1 \le j \le m 1in2,1jm 条件的 ( i , j ) (i,j) (i,j) ,即 ( i , j ) , ( i + 1 , j ) , ( i + 2 , j ) (i,j), (i+1,j), (i+2,j) (i,j),(i+1,j),(i+2,j) 单元格中存在形状相同的饼干。
  • 不存在满足 1 ≤ i ≤ n − 2 , 1 ≤ j ≤ m − 2 1 \le i \le n-2, 1 \le j \le m-2 1in2,1jm2 条件的 ( i , j ) (i,j) (i,j) ,即 ( i , j ) , ( i + 1 , j + 1 ) , ( i + 2 , j + 2 ) (i,j), (i+1,j+1), (i+2,j+2) (i,j),(i+1,j+1),(i+2,j+2) 单元格中有形状相同的饼干。
  • 不存在满足 1 ≤ i ≤ n − 2 , 1 ≤ j ≤ m − 2 1 \le i \le n-2, 1 \le j \le m-2 1in2,1jm2 条件的 ( i , j ) (i,j) (i,j) ,即 ( i , j + 2 ) , ( i + 1 , j + 1 ) , ( i + 2 , j ) (i,j+2), (i+1,j+1), (i+2,j) (i,j+2),(i+1,j+1),(i+2,j) 单元格中有形状相同的饼干。

将答案对 998244353 998244353 998244353取模。

分析:

通过打表发现 n , m ≥ 5 n,m \ge 5 n,m5的情况只有 8 8 8种,并且满足要么每行都是两个两个交错,要么每列都是两个两个交错。那么合法方案只需要考虑以下因素:

  • 行还是列为两个两个交错的情况

  • 第一行/列第一个格子是什么

  • 第一行/列第二个格子是什么

每次新加入的点只需要判断是否会使原来的情况不合法即可。

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, m, q;
        cin >> n >> m >> q;
        cout << 8 << endl;
        int ans[8]{};
        while (q--) {
            int x, y;
            string s;
            cin >> x >> y >> s;
            int op = (s[0] == 'c');
            for (int i = 0; i < 8; i++) {
                int tmp1 = (i >> 0) & 1;
                int tmp2 = (i >> 1) & 1;
                int tmp3 = (i >> 2) & 1;
                if (tmp1 == 0) {
                    int t = y % 2;
                    int tmp = op;
                    if (x % 2 != 0)
                        tmp ^= 1;
                    if (y % 4 > 1)
                        tmp ^= 1;
                    if (t == 0 && tmp2 != tmp) {
                        ans[i] = 1;
                    }
                    if (t == 1 && tmp3 != tmp) {
                        ans[i] = 1;
                    }
                } else {
                    int t = x % 2;
                    int tmp = op;
                    if (y % 2 != 0)
                        tmp ^= 1;
                    if (x % 4 > 1)
                        tmp ^= 1;
                    if (t == 0 && tmp2 != tmp) {
                        ans[i] = 1;
                    }
                    if (t == 1 && tmp3 != tmp) {
                        ans[i] = 1;
                    }
                }
            }
            int sum = 0;
            for (int i = 0; i < 8; i++)
                if (ans[i] == 0)
                    sum++;
            cout << sum << endl;
        }
    }
    return 0;
}

赛后交流

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值