Codeforces Round 1011 (Div. 2) A-E 题解
Codeforces Round 1011 (Div. 2) (opens new window)
# A - Serval and String Theory
# Code
#include <bits/stdc++.h>
using namespace std;
int main() {
// freopen ("A.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T; cin >> T;
while (T--) {
int N, K; cin >> N >> K;
string S; cin >> S;
map<char, int> mp;
for (int i = 0; i < N; i++)
mp[S[i]]++;
if (mp.size() == 1) {
cout << "NO\n";
continue;
}
if (K == 0) {
string S_ = S;
reverse(S_.begin(), S_.end());
if (S < S_) cout << "YES\n";
else cout << "NO\n";
}
else {
cout << "YES\n";
}
}
return 0;
}
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
# B - Serval and Final
# Question
给定一个数组 ,你需要进行操作,直到数组长度为
选择两个数 用单个数 替换 区间里面的数
要求最后一个元素为 ,要求给出一种方案,不要求最小化操作次数
# Solution
我的解法比较麻烦
- 如果全 的话,分成两半处理即可
- 如果全非 ,那么 即可
对于有 有非 的,考虑转化成全非
我们发现 的大小为 ,可以做到
每次从头找,如果发现一个 的位置为 ,那么让 和 边上的元素做一次 操作即可消除 位置的 ,然后去模拟题中的操作直到串中没有 或者串的长度为
每次都从头处理,每次模拟 ,总时间复杂度
# Code
#include <bits/stdc++.h>
using namespace std;
void solve() {
int N; cin >> N;
vector<int> A(N + 1);
for (int i = 1; i <= N; i++) cin >> A[i];
map<int, int> mp;
auto Mex = [&] (vector<int> &A) {
mp.clear();
for (int i = 0; i < A.size(); i++)
mp[A[i]] += 1;
for (int i = 0; i > -1 ; i++)
if (mp[i] == 0) return i;
return 0;
};
vector<pair<int, int>> ans;
auto print = [&] () {
assert(N == 1 and A[1] == 0);
cout << ans.size() << '\n';
for (auto [x, y] : ans) cout << x << ' ' << y << '\n';
};
auto check = [&] (int l, int r) {
ans.push_back({l, r});
vector<int> b;
for (int i = l; i <= r; i++)
b.push_back(A[i]);
int m = Mex(b);
A[l] = m;
for (int i = l + 1; i + 1 <= N; i++)
A[i] = A[i + 1];
for (int i = N - (r - l) + 1; i <= N; i++)
A[i] = 0;
N -= (r - l);
};
if (*max_element(A.begin(), A.end()) == 0) {
check(1, 2);
check(2, N);
check(1, N);
print();
return;
}
while (N >= 2) {
int flg = 0;
for (int i = 1; i <= N; i++) {
if (A[i] == 0) {
if (i != N) {
check(i, i + 1);
flg = 1;
break;
}
else {
check(i - 1, i);
flg = 1;
break;
}
}
}
if (!flg)
check(1, N);
}
print();
}
int main() {
freopen ("B.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T; cin >> T;
while (T--) solve();
}
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
# C - Serval and The Formula
# Question
给定 ,需要找到一个非负数 满足 成立,若不存在则输出
# Solution
异或是二进制下不进位的加法,所以
显然 时无解
由于 ,只要保证 的二进制下的低位有足够多的 ,就能保证
而 足够多了,我们求的
# Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
ll x, y; cin >> x >> y;
if (x == y) {
cout << -1 << '\n';
return;
}
ll k = (1ll << 50) - max(x, y);
cout << k << '\n';
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T; cin >> T;
while (T--) solve();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# D - Serval and Kaitenzushi Buffet
# Question
有一个传送带,上有 盘子, 每个盘子上有 片寿司,第 个盘子里的美味程度为
第 分钟,第 个盘子会到 Serval 面前
初始时寿司片计数器 ,第 分钟,他可以选择一个操作:
- 取下第 盘寿司,收益加 , 加
- 吃掉一片
- 什么都不做, 不变
要求在 分钟结束后,
# Solution
先思考一个问题,其实第 时刻取第 盘是一个相对的概念
由于 可以累加无上限,只需要到最后降到 即可
我们假象在第 盘寿司在大于等于 时刻之后都可以拿起,在这个题中和只能在第 时刻拿起是一样的
一种不是最优但是可行的方法是在 处取下寿司,我们标记这些位置
根据之前的结论,在第 的位置可以取下小于等于 分钟的盘子
所以从头往后处理,当遇到一个标记时,找之前的价值最大的盘子取下,这个可以用一个堆实现
# Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
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> vis(n + 1, 0);
for (int i = n - k; i >= 1; i -= k + 1) vis[i] = 1;
priority_queue<int> pq;
ll ans = 0;
for (int i = 1; i <= n; i++) {
pq.push(a[i]);
if (vis[i]) {
ans += pq.top();
// cout << i << " " << pq.top() << '\n';
pq.pop();
}
}
cout << ans << '\n';
}
int main() {
freopen ("D.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T; cin >> T;
while (T--) solve();
return 0;
}
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
# E - Serval and Modulo
# Question
已知长度为 的数组 ,将各个元素对数字 取模后,打乱顺序后得到数组
需要你求出 ,或者说明不存在这样的
# Solution
大体想法肯定是枚举 ,但是发现 的可能值很多,要考虑如何缩小 的取值范围
求和可以得到
所以我们只需要枚举 的因子即可,这个的数量级大约在 ,但实际上最大只有 ,所以总时间复杂度为
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int vis[1000005];
constexpr int INF = 1e9;
void solve() {
int n; cin >> n;
vector<int> a(n + 1), b(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) cin >> b[i];
sort(a.begin() + 1, a.end());
sort(b.begin() + 1, b.end());
ll sum = 0;
for (int i = 1; i <= n; i++) sum += a[i] - b[i];
if (sum == 0) {
if (a == b) {
cout << INF << '\n';
return;
}
else {
cout << -1 << '\n';
return;
}
}
vector<ll> factors;
for (ll i = 1; i * i <= sum; i++) {
if (sum % i == 0) {
factors.push_back(i);
if (i * i != sum) factors.push_back(sum / i);
}
}
auto check = [&] (ll k) {
// cout << k << '
for (int i = 1; i <= n; i++) vis[a[i] % k] += 1;
for (int i = 1; i <= n; i++) vis[b[i]] -= 1;
int flg = 1;
for (int i = 1; i <= n; i++) {
if (vis[a[i] % k] != 0 or vis[b[i]] != 0) {
flg = 0;
break;
}
}
for (int i = 1; i <= n; i++) vis[a[i] % k] = 0, vis[b[i]] = 0;
return flg;
};
for (ll &k : factors) {
if (check(k)) {
cout << k << '\n';
return;
}
}
cout << -1 << '\n';
}
int main() {
// freopen ("E.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T; cin >> T;
while (T--) solve();
return 0;
}
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