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%b3…bn=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 u−1 。
- 完成 3 3 3-rd 部分会使小 A A A的成绩提高 u − 2 u-2 u−2 。
- … \ldots …
- 完成 k k k-th 部分( k ≥ 1 k \ge 1 k≥1 )会使小 A A A的成绩提高 u + 1 − k u+1-k u+1−k 。 u + 1 − k u+1-k u+1−k 的值可以是负数,这意味着完成额外的部分会降低小 A A A的成绩。
给出一个整数
l
l
l 。询问选择一个整数
r
r
r ,使
l
≤
r
≤
n
l \le r \le n
l≤r≤n 和小
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=l∑rai=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[l−1]>u的位置 r 1 r1 r1,以及最后一个 s [ r ] − s [ l − 1 ] ≤ u s[r]-s[l-1] \le u s[r]−s[l−1]≤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)
(i−1,j) (如果
(
i
−
1
,
j
)
(i - 1, j)
(i−1,j) 中包含一块岩石,那么它将从
(
i
,
j
)
(i, j)
(i,j) 移动到
(
n
−
1
,
j
)
(n - 1, j)
(n−1,j) )。
名为
R
T
RT
RT 的机器人最初位于
(
0
,
0
)
(0,0)
(0,0) 。它必须移动到
(
n
−
1
,
m
−
1
)
(n-1,m-1)
(n−1,m−1) 处进行地震救援(移动到最右下方的单元格)。地震不会改变机器人的位置,只会改变世界中岩石的位置。
假设
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+n−1)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 y≤m−1 时, R T RT RT 才能执行此操作)。
注意,
R
T
RT
RT 不能使用操作向左移动,也不能停留在某一位置。
求
R
T
RT
RT 到达
(
n
−
1
,
m
−
1
)
(n-1,m-1)
(n−1,m−1) 时不与任何岩石相撞所需的最短时间。如果无法做到,输出
−
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 1≤i≤n,1≤j≤m−2 条件的 ( 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 1≤i≤n−2,1≤j≤m 条件的 ( 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 1≤i≤n−2,1≤j≤m−2 条件的 ( 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 1≤i≤n−2,1≤j≤m−2 条件的 ( 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,m≥5的情况只有 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,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。