Martian148's blog Martian148's blog
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档

Martian148

一只热爱文科的理科生
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档
  • codeforses 题解

    • Codeforces Round 933 (Div. 3) A-G 题解
    • Educational Codeforces Round 168 (Rated for Div. 2) A-E 题解
      • A - Strong Password
        • Solution
        • Code
      • B - Make Three Regions
        • Solution
        • Code
      • C - Even Positions
        • Solution
        • Code
      • D - Maximize the Root
        • Question
        • Solution
        • Code
      • E - Level Up
        • Question
        • Solution
    • Codeforces Round 969 (Div. 2) A-D 题解
    • Codeforces Round 1011 (Div. 2) A-E 题解
    • Educational Codeforces Round 177 (Rated for Div. 2) A-D 题解
    • Codeforces Round 1015 (Div. 1 + Div. 2) A-E 题解
    • Codeforces Round 1016 (Div. 3) A-G 题解
  • atcoder 题解

  • XCPC 题解

  • 校训练赛题解

  • 牛客题解

  • 蓝桥杯题解

  • 典题选讲

  • 杂题

  • 算法题解
  • codeforses 题解
martian148
2024-08-06
目录

Educational Codeforces Round 168 (Rated for Div. 2) A-E 题解

Educational Codeforces Round 168 (Rated for Div. 2) (opens new window)

# A - Strong Password

# Solution

找到两个相同的往里面插入一个不同的即可

# Code

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

void solve() {
    string s; cin >> s;
    for (int i = 1; i < s.size(); i++) {
        if (s[i] == s[i - 1]) {
            string t = s;
            char c = s[i] == 'a' ? 'b' : 'a';
            t.insert(t.begin() + i, c);
            cout << t << '\n';
            return;
        }
    }
    char c = s[0] == 'a' ? 'b' : 'a';
    cout << c << s << '\n';
}

int main() {
    // freopen ("A.in", "r", stdin);
    ios::sync_with_stdio(false);
    int T; cin >> T;
    while (T--) solve();
    return 0;
}
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

# B - Make Three Regions

# Solution

找到这样一个区块

...
x.x
1
2

说明在第一行的中间可以放置一个

然后交换一二行再跑一次

# Code

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

int calc(vector<int> a, vector<int> b, int n) {
    int res = 0;
    for (int i = 2; i + 1 <= n; i++) {
        if (a[i] == 0 && a[i - 1] == 0 && a[i + 1] == 0)
        if (b[i] == 0 && b[i - 1] == 1 && b[i + 1] == 1)
            res += 1;
    }
    return res;
}

void solve() {
    int n; cin >> n;
    vector<int> a(n + 2, 0), b(n + 2, 0);
    a[0] = a[n + 1] = b[0] = b[n + 1] = 1;
    for (int i = 1; i <= n; i++) {
        char x; cin >> x;
        if (x == 'x') a[i] = 1;
        else a[i] = 0;
    }
    for (int i = 1; i <= n; i++) {
        char x; cin >> x;
        if (x == 'x') b[i] = 1;
        else b[i] = 0;
    }
    int ans = calc(a, b, n) + calc(b, a, n);
    cout << ans << '\n';
}

int main() {
    freopen ("B.in", "r", stdin);
    ios::sync_with_stdio(false);
    int T; cin >> T;
    while (T--) solve();
    return 0;
}
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

# C - Even Positions

# Solution

贪心得想,左括号和右括号肯定越近越好

所以对于一个 _ 如果里面的左括号较多,我们放置左括号,否则放置右括号,然后我们把右括号的位置塞入一个栈中

对于一个给定的右括号,如果前面的左括号个数不够了,就需要把栈内的一个右括号变成左括号来弥补左括号较少的情况

最后 O(n)O(n)O(n) 计算结果即可

# Code

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

void solve() {
    int n; cin >> n;
    string s; cin >> s;
    int cnt = 0;
    stack<int> st;
    for (int i = 0; i < s.size(); i++) {
        if (s[i] == '(') cnt += 1;
        else if (s[i] == '_') {
            if (cnt > 0) {
                s[i] = ')'; cnt -= 1; st.push(i);
            }
            else {
                cnt += 1; s[i] = '(';
            }
        }
        else if (s[i] == ')') {
            cnt -= 1;
            if (cnt < 0) {
                int pos = st.top(); st.pop();
                s[pos] = '(';
                cnt += 2;
            }
        }
    }
    while (cnt < 0) {
        int pos = st.top(); st.pop();
        s[pos] = '(';
        cnt += 2;
    }
    while (!st.empty()) st.pop();
    long long ans = 0;
    for (int i = 0; i < s.size(); i++) {
        if (s[i] == '(') st.push(i);
        else {
            int pos = st.top(); st.pop();
            ans += i - pos;
        }
    }
    cout << ans << '\n';
}

int main() {
    freopen ("C.in", "r", stdin);
    ios::sync_with_stdio(false);
    int T; cin >> T;
    while (T--) solve();
    return 0;
}
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
47
48
49
50
51

# D - Maximize the Root

# Question

你将得到一棵有根树,共有 nnn 个顶点。树中的顶点编号从 111 到 nnn,根是顶点 111。在第 iii 个顶点上写有值 aia_iai​。

您可以执行以下操作任意次数(可能为零):选择一个至少有一个子节点的顶点 vvv;将 ava_vav​ 增加 111;并将 vvv 的子树中的所有顶点 uuu(除 vvv 本身外)的 aua_uau​ 减少 111。但是,在每次操作后,所有顶点上的值应为非负数。

您的任务是计算使用上述操作可能写在根上的最大可能值。

# Solution

显然二分答案,考虑如何 check

对于一个 mid,根节点和 mid 的差为 ddd,那么就需要把子树都减少 ddd

对于一个节点,如果前面减少了 preprepre,当前节点的值为 a[u]a[u]a[u] ,那么 uuu 的子树就需要减少 pre−a[u]pre-a[u]pre−a[u]

这样递归处理,直到处理到叶子节点即可

# Code

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

void solve() {
    int n; cin >> n;
    string s; cin >> s;
    int cnt = 0;
    stack<int> st;
    for (int i = 0; i < s.size(); i++) {
        if (s[i] == '(') cnt += 1;
        else if (s[i] == '_') {
            if (cnt > 0) {
                s[i] = ')'; cnt -= 1; st.push(i);
            }
            else {
                cnt += 1; s[i] = '(';
            }
        }
        else if (s[i] == ')') {
            cnt -= 1;
            if (cnt < 0) {
                int pos = st.top(); st.pop();
                s[pos] = '(';
                cnt += 2;
            }
        }
    }
    while (cnt < 0) {
        int pos = st.top(); st.pop();
        s[pos] = '(';
        cnt += 2;
    }
    while (!st.empty()) st.pop();
    long long ans = 0;
    for (int i = 0; i < s.size(); i++) {
        if (s[i] == '(') st.push(i);
        else {
            int pos = st.top(); st.pop();
            ans += i - pos;
        }
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    int T; cin >> T;
    while (T--) solve();
    return 0;
}
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
47
48
49
50

# E - Level Up

# Question

Monocarp 从等级 111 开始游戏。他即将与 nnn 只怪物进行战斗,按照从 111 到 nnn 的顺序。第 iii 只怪物的等级为 aia_iai​

对于给定顺序中的每只怪物,Monocarp 的遭遇如下:

  • 如果 Monocarp 的等级严格高于怪物的等级,则怪物会逃跑;
  • 否则,Monocarp 会与怪物战斗。

在每次与怪物战斗 kkk 次后,Monocarp 的等级会增加111

给出 qqq 个查询

  • ixi~xi x:如果参数kkk等于 xxx ,Monocarp 是否会与第iii只怪物战斗(或者这只怪物会逃跑)

# Solution

可以说,根号分治非常强大

首先,肯定要把询问离线下来,按照 kkk 分组

对于一个 kkk 如果 k≤Bk \le Bk≤B 那么直接暴力跑就好了

如果 k>Bk>Bk>B,那么总的等级数不会超过 nB\frac{n}{B}Bn​,我们可以开 nB\frac{n}{B}Bn​ 个前缀和 pre[j][i]pre[j][i]pre[j][i] 表示 表示前 iii 个数中大于 jjj 的数的个数

那么对于每个询问,假设我们现在的位置是 pospospos,等级为 nownownow,那么我们下一个升级的位置就是 第一个满足 pre[j][i]>=pre[now][pos]+kpre[j][i]>=pre[now][pos]+kpre[j][i]>=pre[now][pos]+k 的位置,显然可以二分得出,这部分的时间复杂度是个调和计数,大约为 O(nlog⁡2n)O(n\log^2n)O(nlog2n)

取 B=1000B=1000B=1000 可以通过此题

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

constexpr int M = 300, B = 1000;

void solve() {
    int n, q; cin >> n >> q;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) cin >> a[i];
    vector<vector<int>> pre(M, vector<int>(n + 1, 0)); // pre[j][i] 表示前 i 个数中大于 j 的数的个数
    for (int j = 0; j < M; j++)
        for (int i = 1; i <= n; i++) 
            pre[j][i] = pre[j][i - 1] + (a[i] > j); 
    
    vector<vector<pair<int, int>>> ask(n + 1);
    vector<int> ans(q + 1, 0);
    for (int i = 1; i <= q; i++) {
        int id, k; cin >> id >> k;
        ask[k].push_back({id, i});
    }

    for (int k = 1; k <= n; k++) {
        if (ask[k].empty()) continue;
        sort(ask[k].begin(), ask[k].end());

        if (k <= B) {
            int now = 1, cnt = 0, it = 0;
            for (int i = 1; i <= n; i++) {
                while (it < ask[k].size() && ask[k][it].first == i) {
                    ans[ask[k][it].second] = a[i] >= now;
                    ++it;
                }
                if (a[i] >= now && ++cnt == k) ++now, cnt = 0;
            }
        }
        else {
            int pos = 0, now = 0, it = 0;
            while (pos <= n) {
                pos = lower_bound(pre[now].begin(), pre[now].end(), pre[now][pos] + k) - pre[now].begin();
                // 跳到第一个大于 pre[now][pos] + k 的位置
                now += 1;
                while (it < ask[k].size() && ask[k][it].first <= pos) {
                    ans[ask[k][it].second] = a[ask[k][it].first] >= now;
                    ++it;
                }
            }
        }
    }

    for (int i = 1; i <= q; i++) cout << (ans[i] ? "YES" : "NO") << "\n";
}

int main() {
    ios::sync_with_stdio(0);
    int T; T = 1;
    while (T--) solve();
    return 0;
}
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
47
48
49
50
51
52
53
54
55
56
57
58
上次更新: 2025/04/08, 18:03:31
Codeforces Round 933 (Div. 3) A-G 题解
Codeforces Round 969 (Div. 2) A-D 题解

← Codeforces Round 933 (Div. 3) A-G 题解 Codeforces Round 969 (Div. 2) A-D 题解→

最近更新
01
Java基础语法
05-26
02
开发环境配置
05-26
03
pink 老师 JavaScript 学习笔记
05-26
更多文章>
Theme by Vdoing | Copyright © 2024-2025 Martian148 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式