ACM 协会第一次周赛

A. Rapids 学说话

思路:

  • 操作分为两步
    • 第一步:加 Start
    • 第二步:替换 GenshinImpact
  • 然后模拟即可

时间复杂度:\(O(n * m + n * k + (n/m) * log(n/m))\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);

std::string str = "GenshinImpact";

int n;
std::cin >> n;

std::string s;
std::cin >> s;

int len = str.length();

std::vector<int> p;
for (int i = 0; i + len <= n; i++) {
if (s.substr(i, len) == str) {
p.push_back(i + len);
}
}

std::sort(p.rbegin(), p.rend());

for (int i = 0; i < p.size(); i++) {
s.insert(p[i], "Start");
}

while (s.find(str) != std::string::npos) {
for (int i = 0; i + len < s.size(); i++) {
if (s.substr(i, len) == str) {
s = s.substr(0, i) + "ACM" + s.substr(i + len);
break;
}
}
}
std::cout << s << "\n";

return 0;
}

Python 解法

1
2
3
n = input()
s = input()
print(str.replace(s, "GenshinImpact", "ACMStart"))

B. Rapids 学跳跃

思路:

  • 一定要跳到最后一个位置,所以最后一个位置一定要走。
  • 可以贪心的思考,一定要去掉前 n - 1 个位置中的最大的 m 个,这样使得结果一定是最小的。

时间复杂度:\(O(nlogn)\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void solve() {
int n, m;
std::cin >> n >> m;

int a[n];
for (int i = 0; i < n; i++) {
std::cin >> a[i];
}
i64 ans = a[n - 1];
std::sort(a, a + n - 1);
for (int i = 0; i + m + 1 < n; i++) {
ans += a[i];
}
std::cout << ans << "\n";
}

C. Rapids 学走路

思路:

  • 前缀和板子题,如果不懂,请学习前缀和

时间复杂度:\(O(n)\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);

int n, q;
std::cin >> n >> q;

int a[n] = {};
for (int i = 0; i < n; i++) {
std::cin >> a[i];
}
i64 s[n + 1] = {0};
for (int i = 0; i < n; i++) {
s[i + 1] = s[i] + a[i];
}

while (q--) { // O(1) 查询
int l, r;
std::cin >> l >> r;

std::cout << s[r] - s[l - 1] << "\n";
}

return 0;
}

D. 图图的生存率

思路:

  • 直接暴力枚举所有情况,或者用数学推理一下
  • 这题赛时出现最多的就是 RE,很多同学几乎都没考虑除 0 的情况

时间复杂度:\(O(10^4 / 1)\)

解法一 (暴力):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void solve() {
int m, a, b;
std::cin >> m >> a >> b;

int ans = 0;
for (int i = 0; i <= 100; i++) {
for (int j = 0; j <= 100; j++) {
if (1LL * i * a + 1LL * j * b <= m) {
ans = std::max(ans, i + 2 * j + 50);
}
}
}
std::cout << std::min(std::max(ans, 75), 100) << "%\n";
}

E. chen 和 cheer 的例会之路

思路:

  • 图论最短路板子题

  • 跑一遍 dijkstra 即可,注意爆 int

时间复杂度:\(O(n^2)\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const int N = 5010;
int n, m, vis[N];
i64 mp[N][N], dist[N];

void dijstra(int u) {
memset(dist, 0x3f, sizeof dist);
dist[u] = 0;
for (int i = 0; i + 1 < n; i++) {
int t = -1;
for (int j = 1; j <= n; j++) {
if (!vis[j] && (t == -1 || dist[t] > dist[j])) {
t = j;
}
}

for (int j = 1; j <= n; j++) {
dist[j] = std::min(dist[j], dist[t] + mp[t][j]);
}
vis[t] = true;
}
}

signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);

std::cin >> n >> m;
memset(mp, 0x3f, sizeof mp);

for (int i = 0; i < m; i++) {
int u, v, w;
std::cin >> u >> v >> w;

mp[u][v] = std::min(mp[u][v], 1LL * w); // 双向边
mp[v][u] = std::min(mp[v][u], 1LL * w);
}

int s, t;
std::cin >> s >> t;

dijstra(s);

std::cout << dist[t] << "\n";

return 0;
}