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 题解
    • 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 题解
      • A - Ideal Generator
        • Code
      • B - Expensive Number
        • Solution
        • Code
      • C - Simple Repetition
        • Solution
        • Code
      • D - Skibidi Table
        • Solution
        • Code
      • E - Min Max MEX
        • Question
        • Solution
        • Code
      • F - Hackers and Neural Networks
        • Question
        • Solution
        • Code
      • G - Shorten the Array
        • Question
        • Solution
        • Code
  • atcoder 题解

  • XCPC 题解

  • 校训练赛题解

  • 牛客题解

  • 蓝桥杯题解

  • 典题选讲

  • 杂题

  • 算法题解
  • codeforses 题解
martian148
2025-04-09
目录

Codeforces Round 1016 (Div. 3) A-G 题解

Codeforces Round 1016 (Div. 3) (opens new window)

# A - Ideal Generator

# Code

点击查看
#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int T; cin >> T;
    while (T--) {
        int x; cin >> x;
        if (x % 2 == 1)
            cout << "YES" << '\n';
        else
            cout << "NO" << '\n';
    }
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# B - Expensive Number

# Solution

显然,变成 111 肯定是最小的答案,思考怎么变成 111,就是所有不为 000 的个数加上最后一个非 000 数字后 000 的个数

# Code

点击查看
#include <bits/stdc++.h>
using namespace std;

void solve() {
    string s;
    int ans = 0, flg = 1;
    cin >> s;
    reverse(s.begin(), s.end());
    for (auto c : s) {
        if (c == '0') {
            ans += flg;
        }
        else {
            ans += 1;
            flg = 0;
        }
    }
    cout << ans - 1 << '\n';
}

int main() {
    freopen ("B.in", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    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

# C - Simple Repetition

# Solution

  • 当 k=1k=1k=1 时,直接判断即可
  • 当 k≠1k\ne 1k​=1 时
    • 如果 n=1n=1n=1 那么需要构造出这个数字,然后判断是否为素数
    • 如果 n≠1n\ne 1n​=1 那么肯定必然不是素数,如果 k=2k=2k=2,nnn 的位数为 222,那么肯定能被 101101101 整除,如果 nnn 的位数为 333 那么肯定能被 100110011001 整除,以此类推

# Code

点击查看
#include <bits/stdc++.h>
using namespace std;

bool is_prime(int n) {
    if (n < 2) return false;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) return false;
    }
    return true;
}

void solve() {
    int n, k; cin >> n >> k;
    if (k == 1) {
        cout << (is_prime(n) ? "YES" : "NO") << '\n';
        return ;
    }
    if (n == 1) {
        int x = 0;
        for (int i = 1; i <= k; i++)
            x = x * 10 + n;
        cout << (is_prime(x) ? "YES" : "NO") << '\n';
        return ;
    }
    cout << "NO" << '\n';
    return ;
}

int main() {
    freopen ("C.in", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    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

# D - Skibidi Table

# Solution

递归好题

对于第一问,定义函数 f(x,y,n)f(x,y,n)f(x,y,n) 表示当边长为 2n2^n2n 时,(x,y)(x,y)(x,y) 位置的值,采用递归思维

  • 当 x≤2n−1,y≤2n−1x \le 2^{n-1},y\le 2^{n-1}x≤2n−1,y≤2n−1 时,说明在左上角,f(x,y,n)=f(x,y,n−1)f(x,y,n)=f(x,y,n-1)f(x,y,n)=f(x,y,n−1)

  • 当 x>2n−1,y>2n−1x> 2^{n-1},y>2^{n-1}x>2n−1,y>2n−1 时,说明在右下角,f(x,y,n)=f(x−2n−1,y−2n−1,n−1)+2n−1×2n−1f(x,y,n)=f(x-2^{n-1},y-2^{n-1},n-1)+2^{n-1}\times2^{n-1}f(x,y,n)=f(x−2n−1,y−2n−1,n−1)+2n−1×2n−1

  • 当 x>2n−1,y≤2n−1x> 2^{n-1},y\le 2^{n-1}x>2n−1,y≤2n−1 时,说明在左下角,f(x,y,n)=f(x−2n−1,y,n−1)+2×2n−1×2n−1f(x,y,n)=f(x-2^{n-1},y,n-1)+2\times 2^{n-1}\times2^{n-1}f(x,y,n)=f(x−2n−1,y,n−1)+2×2n−1×2n−1

  • 当 x≤2n−1,y>2n−1x\le 2^{n-1},y>2^{n-1}x≤2n−1,y>2n−1 时,说明在右上角,f(x,y,n)=f(x,y−2n−1,n−1)+3×2n−1×2n−1f(x,y,n)=f(x,y-2^{n-1},n-1)+3\times 2^{n-1}\times2^{n-1}f(x,y,n)=f(x,y−2n−1,n−1)+3×2n−1×2n−1

对于第二问也是同理,定义 g(d,n)g(d,n)g(d,n) 表示,变长为 2n2^n2n 时,ddd 数字所在的位置

  • 当 d≤2n−1×2n−1d\le 2^{n-1}\times 2^{n-1}d≤2n−1×2n−1 说明在左上角,(x,y)=g(d,n−1)(x,y)=g(d,n-1)(x,y)=g(d,n−1),g(d,n)=(x,y)g(d,n)=(x,y)g(d,n)=(x,y)
  • 当 2n−1×2n−1<d≤2×2n−1×2n−12^{n-1}\times 2^{n-1}<d\le 2\times 2^{n-1}\times 2^{n-1}2n−1×2n−1<d≤2×2n−1×2n−1 ,说明在左下角,(x,y)=g(d−2n−1×2n−1,n−1)(x,y)=g(d-2^{n-1}\times 2^{n-1},n-1)(x,y)=g(d−2n−1×2n−1,n−1),g(d,n)=(x+2n−1,y+2n−1)g(d,n)=(x+2^{n-1},y+2^{n-1})g(d,n)=(x+2n−1,y+2n−1)

后面就不写了,同理

# Code

点击查看
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

ll F[61];

ll query_1 (ll x, ll y, ll n) {
    if (n == 0) return 1;
    ll L = 1ll << n, cnt = L * L / 4;
    if (x <= L / 2 && y <= L / 2)
        return query_1(x, y, n - 1);
    if (x > L / 2 && y > L / 2)
        return query_1(x - L / 2, y - L / 2, n - 1) + cnt;
    if (x > L / 2 && y <= L / 2)
        return query_1(x - L / 2, y, n - 1) + cnt * 2;
    if (x <= L / 2 && y > L / 2)
        return query_1(x, y - L / 2, n - 1) + cnt * 3;
    assert(0);
}

pair<ll, ll> query_2 (ll d, ll n) {
    if (n == 0) return {1, 1};
    ll L = 1ll << n, cnt = L * L / 4;
    if (d <= cnt) {
        auto [x, y] = query_2(d, n - 1);
        return {x, y};
    }
    if (d <= cnt * 2) {
        auto [x, y] = query_2(d - cnt, n - 1);
        return {x + L / 2, y + L / 2};
    }
    if (d <= cnt * 3) {
        auto [x, y] = query_2(d - cnt * 2, n - 1);
        return {x + L / 2, y};
    }
    if (d <= cnt * 4) {
        auto [x, y] = query_2(d - cnt * 3, n - 1);
        return {x, y + L / 2};
    }
    assert(0);
}

void solve() {
    ll n; int q; cin >> n >> q;
    while (q--) {
        string op; cin >> op;
        if (op == "->") {
            ll x, y; cin >> x >> y;
            cout << query_1(x, y, n) << '\n';
        }
        else {
            ll d; cin >> d;
            auto [x, y] = query_2(d, n);
            cout << x << ' ' << y << '\n';
        }
    }
}

int main() {
    freopen ("D.in", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    
    for (int i = 0; i < 61; i++) {
        F[i] = (1LL << i);
    }

    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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

# E - Min Max MEX

# Question

给定一个长度为 nnn 当数组 aaa,和一个整数 kkk

现在你需要把数组 aaa 分成 kkk 段,使得所有段的 mex 的最小值最大

# Solution

二分答案 mid,然后去 check 是否能分出 mid 段

对于 check,记录如果从 0∼mid−10\sim mid-10∼mid−1 这些数字都出现过一次,那就段数 +1+1+1

# Code

点击查看
#include <bits/stdc++.h>
using namespace std;

void solve() {
    int n, k; cin >> n >> k;
    vector<int> a(n + 1);

    for (int i = 1; i <= n; i++)
        cin >> a[i];

    vector<int> b(n + 1, 0);

    auto check = [&] (int m) {
        if (m == 0) return true;
        int cnt = 0, now = 0;
        for (int i = 0; i < m; i++)
            b[i] = 0;
        for (int i = 1; i <= n; i++) {
            if (a[i] < m && b[a[i]] == 0) {
                b[a[i]] = 1;
                now += 1;
            }
            if (now == m) {
                cnt += 1;
                now = 0;
                for (int j = 0; j < m; j++)
                    b[j] = 0;
            }
        }
        return cnt >= k;
    };

    int L = 0, R = n + 1;
    while (L + 1 < R) {
        int mid = (L + R) / 2;
        if (check(mid)) {
            L = mid;
        }
        else {
            R = mid;
        }
    }
    cout << L << '\n';
    return ;
}

int main() {
    freopen ("E.in", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    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
52
53
54

# F - Hackers and Neural Networks

# Question

这个题的题意不是很清楚,读了好久

给定一个长度为 nnn 的字符串数组 aaa,aia_iai​ 是一个字符串

和一个 mmm 个长度为 nnn 的字符串数组 bbb,bj,ib_{j,i}bj,i​ 是一个字符串

现在 ccc 是一个为空的,长度为 nnn 的字符串数组,你需要经过一些操作把 ccc 变成 aaa,操作二选一:

  • 选择一个 jjj,计算机会随机选出现在 ccc 中的一个空位 iii,然后把 bj,ib_{j,i}bj,i​ 复制给 aia_iai​
  • 选择一个位置 iii,令 cic_ici​ 为空串

需要求最小操作次数,无解则输出 −1-1−1

# Solution

先考虑无解,对于每一个 aia_iai​,必然存在一个 jjj 使得 ai=bj,ia_{i}=b_{j,i}ai​=bj,i​,若没有则无解

我们可以构造出一种构造方式,设一个字符串数组 bjb_jbj​ 和 aaa 的不一样的字符串数为 missmissmiss

那么一种可行的方式是:先执行 nnn 次 111 操作,然后对于哪些和 bjb_jbj​ 不一样的位置,执行一次 222 操作,然后针对那个位置一样的 bjb_jbj​ 做一次 111 操作

这样的总次数为 n+2×missn+2\times missn+2×miss

所以只需要找到 miss 最小的 jjj 即可

# Code

点击查看
#include <bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;

void solve() {
    int n, m; cin >> n >> m;
    vector<string> a(n + 1);
    vector<vector<string>> b(m + 1, vector<string>(n + 1));

    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> b[i][j];
        }
    }
    for (int i = 1; i <= n; i ++) {
        int flg = 0;
        for (int j = 1; j <= m; j++) {
            if (a[i] == b[j][i]) {
                flg = 1;
                break;
            }
        }
        if (flg == 0) { // 无解
            cout << "-1\n";
            return;
        }
    }

    int min_miss = INF;
    for (int j = 1; j <= m; j++) {
        int miss = 0;
        for (int i = 1; i <= n; i++) {
            if (a[i] != b[j][i]) {
                miss++;
            }
        }
        min_miss = min(min_miss, miss);
    }
    cout << n + 2 * min_miss << '\n';
    return ;
}

int main() {
    freopen ("F.in", "r", stdin);
    // ios::sync_with_stdio(0);
    // cin.tie(0); cout.tie(0);
    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
52

# G - Shorten the Array

# Question

给定一个长度为 nnn 的数组 bbb 和一个整数 kkk

现在需要你选出两个整数 bi,bjb_i,b_jbi​,bj​,满足 bi⊕bj≥kb_i\oplus b_j\ge kbi​⊕bj​≥k 且 j−i+1,i≤jj-i+1,i\le jj−i+1,i≤j 最小

# Solution

一个很典的题目

建立一颗字典树,字典树的 aia_iai​ 的最后一个节点记录下 iii 的下标,然后维护一个数组 max_son[i] 表示字典树上以 iii 为根节点的子树中的最大下标

然后我们定义查询函数,枚举右边的那个数 jjj,对于一个 x=ajx=a_jx=aj​,我们需要查询在字典树中满足 ai⊕x≥ka_i \oplus x\ge kai​⊕x≥k 的最大下标,

这是一个很经典的做法

枚举 kkk 的每一位,假设当前枚举到第 ccc 位,设 kkk 第 ccc 位为 kck_ckc​,xxx 的第 ccc 位为 xcx_cxc​

  • 若 kc=1k_c=1kc​=1,那么需要 x⊕aix\oplus a_ix⊕ai​ 的这一位为 111,所以要在字典树上往 cxc_xcx​ 的异侧走
  • 若 kc=0k_c=0kc​=0,如果 x⊕aix\oplus a_ix⊕ai​ 的这一位为 111,那么就不需要看后面的位了,需要把当前记录的最大下标和与 xcx_cxc​ 异侧的儿子的 max_son 做比较,然后往 xcx_cxc​ 的同侧走

每次先把 jjj 加入字典树中,然后查询,就可以保证字典树中的 i≤ji\le ji≤j 了

# Code

点击查看
#include <bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;

void solve() {
    int n, k; cin >> n >> k;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    struct Node {
        int x, max_son;
        int ch[2];
        Node() : x(0), max_son(0) {
            ch[0] = ch[1] = -1;
        }
    };
    
    int cnt = 0;
    vector<Node> tree(n * 61);
    
    auto insert = [&] (int x, int id) {
        int cur = 0;
        for (int i = 30; i >= 0; i--) {
            int bit = (x >> i) & 1;
            if (tree[cur].ch[bit] == -1) {
                tree[cur].ch[bit] = ++cnt;
                tree[cnt] = Node();
            }
            cur = tree[cur].ch[bit];
            tree[cur].max_son = max(tree[cur].max_son, id);
        }
        tree[cur].x = id;
    };

    auto query = [&] (int x) {
        int cur = 0, ret = 0;
        for (int i = 30; i >= 0; i--) {
            int bit_k = (k >> i) & 1, bit_x = (x >> i) & 1;
            if (bit_k == 1) {
                cur = tree[cur].ch[bit_x ^ 1];
            }
            else {
                if (tree[cur].ch[bit_x ^ 1] != -1)
                    ret = max(ret, tree[tree[cur].ch[bit_x ^ 1]].max_son);
                cur = tree[cur].ch[bit_x];
            }
            if (cur == -1) break;
        }
        if (cur != -1)
            ret = max(ret, tree[cur].max_son);
        // ret = max(ret, tree[cur].max_son);
        return ret;
    };

    int ans = INF;
    for (int i = 1; i <= n; i++) {
        insert(a[i], i);
        int ret = query(a[i]);
        if (ret > 0) {
            ans = min(ans, i - ret + 1);
        }
    }
    cout << (ans == INF ? -1 : ans) << '\n';
}

int main() {
    freopen ("G.in", "r", stdin);
    freopen ("G.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);

    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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
Codeforces Round 1015 (Div. 1 + Div. 2) A-E 题解
AtCoder Beginner Contest 344 A-G 题解

← Codeforces Round 1015 (Div. 1 + Div. 2) A-E 题解 AtCoder Beginner Contest 344 A-G 题解→

最近更新
01
计算机网络笔记
06-13
02
LLM101 NLP学习笔记
06-02
03
《python科学计算入门》学习笔记
05-30
更多文章>
Theme by Vdoing | Copyright © 2024-2025 Martian148 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式