Codeforces Round 1016 (Div. 3) A-G 题解
Codeforces Round 1016 (Div. 3)
A - Ideal Generator
Code
::: details
#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;
}
:::
B - Expensive Number
Solution
显然,变成
Code
::: details
#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;
}
:::
C - Simple Repetition
Solution
- 当
时,直接判断即可 - 当
时 - 如果
那么需要构造出这个数字,然后判断是否为素数 - 如果
那么肯定必然不是素数,如果 , 的位数为 ,那么肯定能被 整除,如果 的位数为 那么肯定能被 整除,以此类推
- 如果
Code
::: details
#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;
}
:::
D - Skibidi Table
Solution
递归好题
对于第一问,定义函数
-
当
时,说明在左上角, -
当
时,说明在右下角, -
当
时,说明在左下角, -
当
时,说明在右上角,
对于第二问也是同理,定义
- 当
说明在左上角, , - 当
,说明在左下角, ,
后面就不写了,同理
Code
::: details
#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;
}
:::
E - Min Max MEX
Question
给定一个长度为
现在你需要把数组
Solution
二分答案 mid,然后去 check 是否能分出 mid 段
对于 check,记录如果从
Code
::: details
#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;
}
:::
F - Hackers and Neural Networks
Question
这个题的题意不是很清楚,读了好久
给定一个长度为
和一个
现在
- 选择一个
,计算机会随机选出现在 中的一个空位 ,然后把 复制给 - 选择一个位置
,令 为空串
需要求最小操作次数,无解则输出
Solution
先考虑无解,对于每一个
我们可以构造出一种构造方式,设一个字符串数组
那么一种可行的方式是:先执行
这样的总次数为
所以只需要找到 miss 最小的
Code
::: details
#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;
}
:::
G - Shorten the Array
Question
给定一个长度为
现在需要你选出两个整数
Solution
一个很典的题目
建立一颗字典树,字典树的
然后我们定义查询函数,枚举右边的那个数
这是一个很经典的做法
枚举
- 若
,那么需要 的这一位为 ,所以要在字典树上往 的异侧走 - 若
,如果 的这一位为 ,那么就不需要看后面的位了,需要把当前记录的最大下标和与 异侧的儿子的 max_son 做比较,然后往 的同侧走
每次先把
Code
::: details
#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;
}
:::