Featured image of post Codeforces Round #715(Div.2)

Codeforces Round #715(Div.2)

B

题目大意:学生会有一个共享文档文件。每天,学生会的一些成员会在里面写下序列 TMT(Towa Maji Tenshi 的缩写)。然而,有一天,成员们不知怎么地同时将该序列输入到了文档中,导致文档变得一团糟。因此,现在轮到堂岛杉鲁来判断文档是否出现了故障。

数据范围:$1 \le t \le 5000$,$3 \le n < 10^5$,$\sum n \le 10^5$。

思路:

 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
using i128 = __int128_t;
void solve() {
    ll n;
    string s;
    cin >> n >> s;
    ll tem0 = 0, tem1 = 0, tem2 = 0;
    ll tot0 = 0, tot1 = 0;
    rep(i, 0, n - 1) {
        if (s[i] == 'T')
            tot0++;
        else
            tot1++;
    }
    if (tot0 != 2 * tot1) {
        cout << "NO" << endl;
        return;
    }
    int las = 0;
    rep(i, 0, n - 1) {
        if (s[i] == 'M') {
            las++;
            if (tem0 < las) {
                cout << "NO" << endl;
                return;
            }
        } else
            tem0++;
    }
    las = 0, tem0 = 0;
    frep(i, n - 1, 0) {
        if (s[i] == 'M') {
            las++;
            if (tem0 < las) {
                cout << "NO" << endl;
                return;
            }
        } else
            tem0++;
    }
    cout << "YES" << endl;
    return;
}

C

题目大意:学生会正在为运动会的接力赛做准备。学生会共有 $n$ 名成员。他们将在比赛中依次奔跑,第 $i$ 位成员的速度为 $s_i$。第 $i$ 阶段的不均衡度 $d_i$ 定义为前 $i$ 位已经跑过的成员中最大速度与最小速度的差值。形式化地,若 $a_i$ 表示第 $i$ 位参赛成员的速度,则 $d_i = \max(a_1, a_2, \dots, a_i) - \min(a_1, a_2, \dots, a_i)$。你希望最小化所有阶段不均衡度之和 $d_1 + d_2 + \dots + d_n$。为此,你可以改变成员的出场顺序。请问最小可能的总和是多少?

数据范围:$1 \le n \le 2000$,$1 \le s_i \le 10^9$。

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
using i128 = __int128_t;
void solve() {
    ll n;
    cin >> n;
    vl a(n);
    rep(i, 0, n - 1) cin >> a[i];
    ranges::sort(a);
    vvl dp(n + 1, vl(n + 1));
    rep(i, 2, n) {
        rep(j, 0, n - i) { dp[j][j + i - 1] = min(dp[j][j + i - 2], dp[j + 1][j + i - 1]) + (a[j + i - 1] - a[j]); }
    }
    cout << dp[0][n - 1] << endl;
    return;
}

D

题目大意:给定三个长度为 $2n$ 的 01 串,需要构造一个长度不超过 $3n$ 的 01 串,使其至少包含其中两个作为子序列。

数据范围:$1 \le t \le 10^4$,$1 \le n \le 10^5$,$\sum n \le 10^5$。

思路:

  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
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
using i128 = __int128_t;
void solve() {
    ll n;
    cin >> n;
    vector<string> ma(3);
    rep(i, 0, 2) cin >> ma[i];
    int tot0 = 0, tot1 = 0, tot2 = 0;
    rep(i, 0, 2 * n - 1) tot0 += (ma[0][i] == '0');
    rep(i, 0, 2 * n - 1) tot1 += (ma[1][i] == '0');
    rep(i, 0, 2 * n - 1) tot2 += (ma[2][i] == '0');
    if (tot0 < n && tot1 < n) {
        string res = "";
        int i = 0, j = 0;
        while (i <= 2 * n - 1 || j <= 2 * n - 1) {
            while (i <= 2 * n - 1 && ma[0][i] != '1') {
                res.push_back(ma[0][i]);
                i++;
            }
            while (j <= 2 * n - 1 && ma[1][j] != '1') {
                res.push_back(ma[1][j]);
                j++;
            }
            if (i <= 2 * n - 1 && j <= 2 * n - 1) {
                res.push_back('1');
                i++, j++;
            } else {
                while (i <= 2 * n - 1) {
                    res.push_back(ma[0][i]);
                    i++;
                }
                while (j <= 2 * n - 1) {
                    res.push_back(ma[1][j]);
                    j++;
                }
            }
        }
        cout << res << endl;
    } else if (tot0 < n && tot2 < n) {
        string res = "";
        int i = 0, j = 0;
        while (i <= 2 * n - 1 || j <= 2 * n - 1) {
            while (i <= 2 * n - 1 && ma[0][i] != '1') {
                res.push_back(ma[0][i]);
                i++;
            }
            while (j <= 2 * n - 1 && ma[2][j] != '1') {
                res.push_back(ma[2][j]);
                j++;
            }
            if (i <= 2 * n - 1 && j <= 2 * n - 1) {
                res.push_back('1');
                i++, j++;
            } else {
                while (i <= 2 * n - 1) {
                    res.push_back(ma[0][i]);
                    i++;
                }
                while (j <= 2 * n - 1) {
                    res.push_back(ma[2][j]);
                    j++;
                }
            }
        }
        cout << res << endl;
    } else if (tot1 < n && tot2 < n) {
        string res = "";
        int i = 0, j = 0;
        while (i <= 2 * n - 1 || j <= 2 * n - 1) {
            while (i <= 2 * n - 1 && ma[1][i] != '1') {
                res.push_back(ma[1][i]);
                i++;
            }
            while (j <= 2 * n - 1 && ma[2][j] != '1') {
                res.push_back(ma[2][j]);
                j++;
            }
            if (i <= 2 * n - 1 && j <= 2 * n - 1) {
                res.push_back('1');
                i++, j++;
            } else {
                while (i <= 2 * n - 1) {
                    res.push_back(ma[1][i]);
                    i++;
                }
                while (j <= 2 * n - 1) {
                    res.push_back(ma[2][j]);
                    j++;
                }
            }
        }
        cout << res << endl;
    } else if (tot0 >= n && tot1 >= n) {
        string res = "";
        int i = 0, j = 0;
        while (i <= 2 * n - 1 || j <= 2 * n - 1) {
            while (i <= 2 * n - 1 && ma[0][i] != '0') {
                res.push_back(ma[0][i]);
                i++;
            }
            while (j <= 2 * n - 1 && ma[1][j] != '0') {
                res.push_back(ma[1][j]);
                j++;
            }
            if (i <= 2 * n - 1 && j <= 2 * n - 1) {
                res.push_back('0');
                i++, j++;
            } else {
                while (i <= 2 * n - 1) {
                    res.push_back(ma[0][i]);
                    i++;
                }
                while (j <= 2 * n - 1) {
                    res.push_back(ma[1][j]);
                    j++;
                }
            }
        }
        cout << res << endl;
    } else if (tot0 >= n && tot2 >= n) {
        string res = "";
        int i = 0, j = 0;
        while (i <= 2 * n - 1 || j <= 2 * n - 1) {
            while (i <= 2 * n - 1 && ma[0][i] != '0') {
                res.push_back(ma[0][i]);
                i++;
            }
            while (j <= 2 * n - 1 && ma[2][j] != '0') {
                res.push_back(ma[2][j]);
                j++;
            }
            if (i <= 2 * n - 1 && j <= 2 * n - 1) {
                res.push_back('0');
                i++, j++;
            } else {
                while (i <= 2 * n - 1) {
                    res.push_back(ma[0][i]);
                    i++;
                }
                while (j <= 2 * n - 1) {
                    res.push_back(ma[2][j]);
                    j++;
                }
            }
        }
        cout << res << endl;
    } else if (tot1 >= n && tot2 >= n) {
        string res = "";
        int i = 0, j = 0;
        while (i <= 2 * n - 1 || j <= 2 * n - 1) {
            while (i <= 2 * n - 1 && ma[1][i] != '0') {
                res.push_back(ma[1][i]);
                i++;
            }
            while (j <= 2 * n - 1 && ma[2][j] != '0') {
                res.push_back(ma[2][j]);
                j++;
            }
            if (i <= 2 * n - 1 && j <= 2 * n - 1) {
                res.push_back('0');
                i++, j++;
            } else {
                while (i <= 2 * n - 1) {
                    res.push_back(ma[1][i]);
                    i++;
                }
                while (j <= 2 * n - 1) {
                    res.push_back(ma[2][j]);
                    j++;
                }
            }
        }
        cout << res << endl;
    }
    return;
}

E

题目大意:Seiji Maki 不仅喜欢观察关系的展开,他还喜欢观察数字序列,尤其是排列。今天,他关注的是“几乎有序排列”。定义几乎有序排列满足 $a_{i+1} \ge a_i - 1$。给定 $n,k$,求所有几乎有序排列按字典序排序后的第 $k$ 个。

数据范围:$1 \le t \le 1000$,$1 \le n \le 10^5$,$1 \le k \le 10^{18}$,$\sum n \le 10^5$。

思路:

 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
using i128 = __int128_t;
void solve() {
    ll n, k;
    cin >> n >> k;
    if (n <= 63 && (1LL << (n - 1)) < k) {
        cout << -1 << endl;
        return;
    }
    vl res;
    ll l = 1;
    while (l <= n) {
        ll tem = 1;
        while (tem <= n - l + 1) {
            ll tem2 = n - l + 1 - tem;
            ll cnt;
            if (tem2 == 0)
                cnt = 1;
            else if (tem2 <= 63)
                cnt = (1LL << (tem2 - 1));
            else
                cnt = (1LL << 62);
            if (k > cnt) {
                k -= cnt;
                tem++;
            } else
                break;
        }
        frep(i, l + tem - 1, l) res.push_back(i);
        l += tem;
    }
    rep(i, 0, n - 1) cout << res[i] << ' ';
    cout << endl;
    return;
}

F

题目大意:作为一名教师,Riko Hakozaki 经常需要帮助她的学生解决各类学科的问题。今天,她被问到了一个编程任务,内容如下: 给定一个部分边有正权的完全图,需要给未赋值边分配非负权,使所有边权异或和为 $0$,并最小化最终图的 MST 权值。

数据范围:$2 \le n \le 2 \cdot 10^5$,$0 \le m \le \min(2 \cdot 10^5, \frac{n(n-1)}{2})$,$1 \le u_i, v_i \le n$,$1 \le w_i < 2^{30}$。

思路:

 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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
using i128 = __int128_t;
class UnionFind {
    vector<int> fa;
    vector<int> siz;  // 集合大小
public:
    int cc;  // 连通块个数
    UnionFind(int n) : fa(n), siz(n, 1), cc(n) { ranges::iota(fa, 0); }
    int get(int x) {
        if (fa[x] != x) fa[x] = get(fa[x]);
        return fa[x];
    }
    bool is_same(int x, int y) { return get(x) == get(y); }
    bool merge(int from, int to) {
        int x = get(from), y = get(to);
        if (x == y) return false;
        fa[x] = y;
        siz[y] += siz[x];
        cc--;
        return true;
    }
    int get_size(int x) {  // 查询x所在集合大小
        return siz[get(x)];
    }
};
void solve() {
    ll n, m, x, y, z;
    cin >> n >> m;
    vector<vector<pll>> ma(n);
    vector<set<ll>> ma2(n);
    vector<trl> edges;
    ll tem = 0;
    rep(i, 0, m - 1) {
        cin >> x >> y >> z;
        ma[x - 1].emplace_back(y - 1, z);
        ma[y - 1].emplace_back(x - 1, z);
        ma2[x - 1].insert(y - 1);
        ma2[y - 1].insert(x - 1);
        edges.emplace_back(z, x - 1, y - 1);
        tem ^= z;
    }
    set<int> s;
    rep(i, 0, n - 1) s.insert(i);
    int cc = 0;
    UnionFind u(n);
    while (!s.empty()) {
        cc++;
        queue<int> q;
        int st = *s.begin();
        s.erase(s.begin());
        q.push(st);
        while (!q.empty()) {
            auto node = q.front();
            q.pop();
            auto it = s.begin();
            while (it != s.end()) {
                int y = *it;
                if (!ma2[node].count(y)) {
                    q.push(y);
                    it = s.erase(it);
                    u.merge(node, y);
                } else
                    it++;
            }
        }
    }
    if (1LL * n * (n - 1) / 2 - m > n - cc) {
        sort(all(edges));
        ll ans = 0;
        for (auto& [z, x, y] : edges) {
            if (u.merge(x, y)) {
                ans += z;
            }
        }
        cout << ans << endl;
    } else {
        vl vis(m);
        sort(all(edges));
        ll ans = 0;
        ll mixx = tem;
        rep(i, 0, m - 1) {
            auto [z, x, y] = edges[i];
            if (u.merge(x, y)) {
                ans += z;
                vis[i] = 1;
            }
        }
        UnionFind u2(n);
        rep(i, 0, m - 1) {
            auto [z, x, y] = edges[i];
            if (u2.merge(x, y)) {
                if (!vis[i]) mixx = min(mixx, z);
            }
        }
        cout << ans + mixx << endl;
    }
    return;
}