Codeforces Round 1017 (Div. 4) 题解(A~H)
A
#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 1000010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int a[N];
signed main() {
// freopen("debug.err", "w", stderr);
cin.tie(0)->sync_with_stdio(false);
cout << fixed << setprecision(15);
srand(time(0));
int T;
cin >> T;
while (T--) {
string a, b, c;
cin >> a >> b >> c;
cout << a[0] << b[0] << c[0] << '\n';
}
return 0;
}
B
#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 1000010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int a[N];
signed main() {
// freopen("debug.err", "w", stderr);
cin.tie(0)->sync_with_stdio(false);
cout << fixed << setprecision(15);
srand(time(0));
int T;
cin >> T;
while (T--) {
int n, m, l, r;
cin >> n >> m >> l >> r;
int diff = n - m;
if (r >= diff) cout << l << ' ' << r - diff << '\n';
else {
diff -= r;
r = 0;
cout << l + diff << ' ' << r << '\n';
}
}
return 0;
}
C
观察到 \(2\sim n+n\) 都可以直接在 \(a\) 中找出,因此只需要找没有出现过的数就是第一个元素的值
时间复杂度为 \(O(n^2)\)。
#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 1000010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int a[810][810];
signed main() {
// freopen("debug.err", "w", stderr);
cin.tie(0)->sync_with_stdio(false);
cout << fixed << setprecision(15);
srand(time(0));
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
cin >> a[i][j];
set<int> se;
for (int i = 1; i <= n + n; ++i) se.emplace(i);
for (int i = 1; i <= n; ++i) se.erase(a[1][i]);
for (int i = 2; i <= n; ++i) se.erase(a[i][n]);
cout << *se.begin() << ' ';
for (int i = 1; i <= n; ++i) cout << a[1][i] << ' ';
for (int i = 2; i <= n; ++i) cout << a[i][n] << ' ';
cout << '\n';
}
return 0;
}
D
把两个字符串均划分为若干段连续的相同字符,合法则需要满足:
- 两个字符串划分的段数相等,且对应段的字符也相同。
- 假设第 \(i\) 段在 \(S\) 中长度为 \(c_1\),在 \(T\) 中长度为 \(c_2\),则需要满足 \(c_2\le c_1\le 2c_2\)。
直接用两个指针扫描数组然后贪心模拟,时间复杂度为 \(O(n)\)。
#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 1000010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
char s[N], t[N];
signed main() {
// freopen("debug.err", "w", stderr);
// cin.tie(0)->sync_with_stdio(false);
cout << fixed << setprecision(15);
srand(time(0));
int T;
cin >> T;
while (T--) {
scanf("%s%s", s + 1, t + 1);
int n = strlen(s + 1), m = strlen(t + 1);
int p1 = 1, p2 = 1, ok = 1;
while (p1 <= n && p2 <= m) {
int c1 = 0, c2 = 0, lp1 = p1, lp2 = p2;
while (p1 <= n && s[p1] == s[lp1]) ++p1;
while (p2 <= m && t[p2] == t[lp2]) ++p2;
c1 = p1 - lp1, c2 = p2 - lp2;
if (c1 <= c2 && 2 * c1 >= c2 && s[lp1] == t[lp2]) ;
else {
ok = 0;
break;
}
}
if (!ok) cout << "NO\n";
else if ((p1 > n && p2 <= m) || (p1 <= n && p2 > m)) cout << "NO\n";
else cout << "YES\n";
}
return 0;
}
E
拆位然后按位考虑答案,用前缀和维护即可,时间复杂度为 \(O(n\log V)\)
#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 200010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int a[N];
int pre[N][32];
signed main() {
// freopen("debug.err", "w", stderr);
cin.tie(0)->sync_with_stdio(false);
cout << fixed << setprecision(15);
srand(time(0));
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
int mx = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < 30; ++j)
pre[i][j] = pre[i - 1][j] + (a[i] >> j & 1);
}
for (int i = 1; i <= n; ++i) {
int sum = 0;
for (int j = 0; j < 30; ++j) {
int cnt = pre[i - 1][j] + (pre[n][j] - pre[i][j]);
if (a[i] >> j & 1) cnt = n - 1 - cnt;
sum += (1ll << j) * cnt;
}
mx = max(mx, sum);
}
cout << mx << '\n';
}
return 0;
}
F
分类讨论:若 \(k\) 可以被分为 \(x_1x_2\) 并满足 \(x_1,x_2>1,x_1\mid n,x_2\mid m\),则可以把数组划分为若干个 \(x_1\times x_2\) 的子数组然后直接按 \(1\sim k\) 的顺序给数组染色,否则必然满足 \(k\mid n\) 或 \(k\mid m\),就直接按顺序染色然后为了避免相邻两个元素相同,轮换一下即可。
时间复杂度为 \(O(nm)\)。
#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 200010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int isprime(int x) {
if(x < 2) return 0;
for (int i = 2; i * i <= x; ++i)
if (x % i == 0) return 0;
return 1;
}
int pos[N];
signed main() {
// freopen("debug.err", "w", stderr);
cin.tie(0)->sync_with_stdio(false);
cout << fixed << setprecision(15);
srand(time(0));
int T;
cin >> T;
while (T--) {
int n, m, k;
cin >> n >> m >> k;
vector<vector<int>> a(n + 2);
for (int i = 0; i < n + 2; ++i) a[i].resize(m + 2);
if (n % k == 0) {
// cerr << "wa\n";
for (int i = 0; i <= n + 1; ++i) pos[i] = 1;
for (int i = 0; i < m; ++i) {
int start = 1;
for (int j = 0; j < n; j += k) {
int nw = pos[j];
for (int p = j; p < j + k; ++p) {
a[p + 1][i + 1] = nw;
++nw;
if (nw > k) nw = 1;
}
++pos[j];
if (pos[j] > k) pos[j] = 1;
}
}
} else if (m % k == 0) {
for (int i = 0; i <= m + 1; ++i) pos[i] = 1;
for (int i = 0; i < n; ++i) {
int start = 1;
for (int j = 0; j < m; j += k) {
int nw = pos[j];
for (int p = j; p < j + k; ++p) {
a[i + 1][p + 1] = nw;
++nw;
if (nw > k) nw = 1;
}
++pos[j];
if (pos[j] > k) pos[j] = 1;
}
}
} else {
vector<int> fact;
for (int i = 2; i * i <= k; ++i)
if (k % i == 0) {
fact.emplace_back(i);
fact.emplace_back(k / i);
}
int x = -1, y = -1;
for (int &i : fact)
if (n % i == 0 && m % (k / i) == 0) {
x = i, y = k / i;
break;
}
for (int i = 0; i < n; i += x) {
for (int j = 0; j < m; j += y) {
int idx = 1;
for (int p = i; p < i + x; ++p)
for (int q = j; q < j + y; ++q)
a[p + 1][q + 1] = idx++;
}
}
}
for (int i = 0; i < n; ++i, cout << '\n')
for (int j = 0; j < m; ++j) cout << a[i + 1][j + 1] << ' ';
}
return 0;
}
G
用双端队列随便维护一下答案,再打一个标记表示当前数组是否被翻转即可,时间复杂度为 \(O(n)\)。
#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 200010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int isprime(int x) {
if(x < 2) return 0;
for (int i = 2; i * i <= x; ++i)
if (x % i == 0) return 0;
return 1;
}
signed main() {
// freopen("debug.err", "w", stderr);
cin.tie(0)->sync_with_stdio(false);
cout << fixed << setprecision(15);
srand(time(0));
int T;
cin >> T;
while (T--) {
int q, n = 0;
cin >> q;
int pre = 0, sum = 0;
deque<int> Q;
int tag = 0;
while (q--) {
int o;
cin >> o;
if (o == 1) {
if (!tag) {
sum += pre - n * Q.back();
Q.emplace_front(Q.back());
Q.pop_back();
} else {
sum += pre - n * Q.front();
Q.emplace_back(Q.front());
Q.pop_front();
}
} else if (o == 2) {
tag ^= 1;
sum = pre * (n + 1) - sum;
} else {
int x;
cin >> x;
++n;
pre += x;
sum += n * x;
if (!tag) Q.emplace_back(x);
else Q.emplace_front(x);
}
cout << sum << '\n';
}
}
return 0;
}
H
观察到 \(k\) 最多减 \(\log V\) 次就会变成 \(1\),而 \(k=1\) 的情况是简单的,所以直接枚举因子二分出 \(k\) 的值下一次会在哪里减少,暴力模拟减少的过程即可。容易证明时间复杂度正确。
#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 100010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int a[N];
vector<int> divi[N], scc[N];
signed main() {
// freopen("debug.err", "w", stderr);
cin.tie(0)->sync_with_stdio(false);
cout << fixed << setprecision(15);
srand(time(0));
int T;
cin >> T;
for (int i = 2; i < N; ++i)
for (int j = i; j < N; j += i)
divi[j].emplace_back(i);
while (T--) {
int n, q;
cin >> n >> q;
for (int i = 1; i <= n; ++i) cin >> a[i], scc[a[i]].emplace_back(i);
while (q--) {
int k, l, r, sum = 0, ccf = 0, las = k;
cin >> k >> l >> r;
las = k;
for (int i = l; i <= r; ) {
if (las == 1) {
sum += r - i + 1;
break;
}
int ri = r + 1;
for (int &j : divi[las])
if (scc[j].size()) {
auto it = lower_bound(scc[j].begin(), scc[j].end(), i);
if (it != scc[j].end() && *it <= r) ri = min(ri, *it);
if (ri == r + 1) {
sum += (r - i + 1) * las;
break;
} else {
sum += (ri - i) * las;
assert(las % a[ri] == 0);
while (las % a[ri] == 0) las /= a[ri];
sum += las, i = ri + 1;
}
}
cout << sum << '\n';
}
for (int i = 1; i <= n; ++i) scc[a[i]].clear();
}
return 0;
}