Codeforces Round 1016 (Div. 3)
注: G 暂时不会
A
题目大意
一个正整数\(k\),如果对于任意不小于\(k\)的数\(n\),都能写出长度为\(k\)且总和为n的回文数组,则输出YES,否则输出NO。
解题思路
- \(k\)是奇数,输出YES。
- \(k\)是偶数,输出NO。
代码实现
#include<bits/stdc++.h>
void Main() {
int n;
std::cin >> n;
if (n & 1) {
std::cout << "YES" << '\n';
} else {
std::cout << "NO" << '\n';
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) {
Main();
}
return 0;
}
B
题目大意
一个正整数\(n\),各个数位之和为\(m\),它的代价为\(n\div m\)。
为了使代价减小,可以删除某些数位,但是最后不能为\(0\)。
输出代价最小时,删除数字的最小数量。
解题思路
- \(n\)很大,需要高精度。
- 分子和分母都为正整数,所以最小代价就是\(1\),只剩下一个数字。
- 找到不是\(0\)的最低数位,删掉高位的非零数和低位的\(0\)。
代码实现
#include<bits/stdc++.h>
void Main() {
std::string s;
std::cin >> s;
int n = s.size();
for (int i = n - 1; i >= 0; i--) {
if (s[i] != '0') {
std::cout << n - 1 - count(s.begin(), s.begin() + i, '0') << '\n';
return;
}
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) {
Main();
}
return 0;
}
C
题目大意
正整数\(x,k\),\(y\)是\(x\)的十进制重复\(k\)次,如果\(y\)是质数,输出YES,否则输出NO。
解题思路
- 当\(x=1,k=1\)时,输出NO。
- 当\(x\geq 2,k\geq 2\)时,\(y=x\times (p^{k-1}+p^{k-2}+\cdots+p^{1}+p^{0})\),\(p\)是比\(x\)大的最小的10的次幂。
所以\(y\)一定有因子\(x\),输出NO。 - 其他情况,暴力判断因子。
- 时间复杂度\(O(t\times \sqrt{x})\)。
代码实现
#include<bits/stdc++.h>
void Main() {
int x, k;
std::cin >> x >> k;
if (x >= 2 && k >= 2) {
std::cout << "NO" << '\n';
return;
}
if (x == 1) {
if (k == 1) {
std::cout << "NO" << '\n';
return;
}
int y = 0;
for (int i = 0; i < k; i++) {
y = y * 10 + 1;
}
for (int i = 2; i * i <= y; i++) {
if (y % i == 0) {
std::cout << "NO" << '\n';
return;
}
}
std::cout << "YES" << '\n';
return;
}
for (int i = 2; i * i <= x; i++) {
if (x % i == 0) {
std::cout << "NO" << '\n';
return;
}
}
std::cout << "YES" << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) {
Main();
}
return 0;
}
D
解题思路
- 递归分治
- 标准的板子题,就是代码不太好写。
代码实现
#include<bits/stdc++.h>
using i64 = long long;
i64 find(i64 i, int lx, int ly, int rx, int ry, int a, int b) {
if (lx == a && ly == b) {
return i;
}
int midx = lx + rx >> 1, midy = ly + ry >> 1;
i64 sum = (1LL * midx - lx + 1) * (1LL * midy - ly + 1);
if (a <= midx && b <= midy) {
return find(i, lx, ly, midx, midy, a, b);
}
if (a <= midx && b > midy) {
return find(i + 3 * sum, lx, midy + 1, midx, ry, a, b);
}
if (a > midx && b <= midy) {
return find(i + 2 * sum, midx + 1, ly, rx, midy, a, b);
}
return find(i + sum, midx + 1, midy + 1, rx, ry, a, b);
}
std::pair<int, int> get(i64 d, i64 l, i64 r, int lx, int ly, int rx, int ry) {
if (lx == rx && ly == ry) {
return {lx, ly};
}
i64 k = (r - l + 1) >> 2;
int midx = lx + rx >> 1, midy = ly + ry >> 1;
if (d < l + k) {
return get(d, l, l + k - 1, lx, ly, midx, midy);
}
if (d < l + 2 * k) {
return get(d, l + k, l + 2 * k - 1, midx + 1, midy + 1, rx, ry);
}
if (d < l + 3 * k) {
return get(d, l + 2 * k, l + 3 * k - 1, midx + 1, ly, rx, midy);
}
return get(d, l + 3 * k, r, lx, midy + 1, midx, ry);
}
void Main() {
int n, q;
std::cin >> n >> q;
while (q--) {
std::string op;
int x, y;
i64 d;
std::cin >> op;
if (op == "->") {
std::cin >> x >> y;
std::cout << find(1, 1, 1, 1 << n, 1 << n, x, y) << '\n';
} else {
std::cin >> d;
auto [dx, dy] = get(d, 1, (1LL << n) * (1LL << n), 1, 1, (1 << n), (1 << n));
std::cout << dx << " " << dy << '\n';
}
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) {
Main();
}
return 0;
}
E
题目大意
一个长度为\(n\)的数组\(a\),将数组划分成\(k\)段子数组,代价\(x\)为每段\(mex\)中的最小值。
划分时使\(x\)尽可能大,输出\(x\)的最大值。
解题思路
- 二分答案
- check时,遇到\(mex\geq x\)就重新开一段,判断能否划分成\(k\)段及以上。
代码实现
#include<bits/stdc++.h>
void Main() {
int n, k;
std::cin >> n >> k;
std::vector<int> a(n);
for (int i = 0; i < n; i++) {
std::cin >> a[i];
}
int l = 0, r = n;
auto check = [&] (int x) -> bool {
int cnt = 0, mex = 0;
std::vector<bool> mp(x);
for (int i = 0; i < n; i++) {
if (a[i] < x) {
mp[a[i]] = 1;
}
while (mp[mex]) {
mex++;
}
if (mex >= x) {
mex = 0;
cnt++;
fill(mp.begin(), mp.end(), 0);
}
}
return cnt >= k;
};
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid)) {
l = mid;
} else {
r = mid - 1;
}
}
std::cout << l << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) {
Main();
}
return 0;
}
F
解题思路
- 模拟
- chose存下神经网络\(i\)可以处理的位置\(j\),sol存下可以处理第\(j\)位的神经网络\(i\)。
- 每次选择处理数量最多的神经网络\(pos\),然后把其他神经网络上\(pos\)处理过的位置删掉,这样就可以在下一次直接加\(2\times size\)(操作2变空白,再操作1放上合法的)。
好像做麻烦了,看到很多佬直接\(3\times n-2\times ans\)。
代码实现
#include<bits/stdc++.h>
void Main() {
int n, m;
std::cin >> n >> m;
std::vector<std::string> a(n);
std::vector b(m, std::vector<std::string>(n));
for (int i = 0; i < n; i++) {
std::cin >> a[i];
}
std::vector<std::set<int>> chose(m);
std::vector<std::vector<int>> sol(n);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
std::cin >> b[i][j];
if (b[i][j] == a[j]) {
chose[i].insert(j);
sol[j].push_back(i);
}
}
}
int ans = 0;
for (int s = 0; s < n; ) {
int pos = 0;
for (int i = 0; i < m; i++) {
if (chose[i].size() > chose[pos].size()) {
pos = i;
}
}
if (chose[pos].empty()) {
std::cout << -1 << '\n';
return;
}
if (!ans) {
ans = n;
s += chose[pos].size();
} else {
ans += 2 * chose[pos].size();
s += chose[pos].size();
}
for (auto i : chose[pos]) {
for (auto j : sol[i]) {
if (j != pos) {
chose[j].erase(i);
}
}
}
chose[pos].clear();
}
std::cout << ans << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) {
Main();
}
return 0;
}