Codeforces Round #736 (Div. 2)【ABCD】
比赛链接:https://codeforces.com/contest/1549
A. Gregor and Cryptography
题解
构造。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int p;
cin >> p;
cout << 2 << ' ' << (p - 1) << "\n";
}
return 0;
}
B. Gregor and the Pawn Game
题解
贪心,尽可能地靠一边放。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<string> MP(2);
for (int i = 0; i < 2; i++) {
cin >> MP[i];
}
vector<bool> vis(n);
for (int i = 0; i < n; i++) {
if (MP[1][i] == '0') {
continue;
}
if (i - 1 >= 0 and MP[0][i - 1] == '1' and not vis[i - 1]) {
vis[i - 1] = true;
} else if (MP[0][i] == '0' and not vis[i]) {
vis[i] = true;
} else if (i + 1 < n and MP[0][i + 1] == '1' and not vis[i + 1]) {
vis[i + 1] = true;
}
}
cout << count(vis.begin(), vis.end(), true) << "\n";
}
return 0;
}
C. Web of Lies
题解
类似拓扑排序的思想,将无向边转化为有向边,假设由较小点指向较大点,每次询问即统计出度为 0 的点。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<int> out(n);
set<int> st;
auto opt = [&](bool add) {
int u, v;
cin >> u >> v;
--u, --v;
out[min(u, v)] += add ? 1 : -1;
st.erase(u), st.erase(v);
if (out[u] == 0) {
st.insert(u);
}
if (out[v] == 0) {
st.insert(v);
}
};
for (int i = 0; i < m; i++) {
opt(true);
}
for (int u = 0; u < n; u++) {
if (out[u] == 0) {
st.insert(u);
}
}
int q;
cin >> q;
while (q--) {
int op;
cin >> op;
if (op == 1) {
opt(true);
} else if (op == 2) {
opt(false);
} else {
cout << st.size() << "\n";
}
}
return 0;
}
D. Integers Have Friends
题解
不妨先考察较小的情况,如果两个数 \(a\) 和 \(b\) 同余,它们与余数 \(m\) 的关系。
假设 \(a \lt b\) ,易得:
\(a = a\)
\(b = a + (b - a)\)
\(a\) 和 \(b\) 对 \(m\) 取余即:
\(a \bmod m\)
\(a \bmod m + (b - a) \bmod m\)
所以,若 \(a\) 和 \(b\) 同余,那么 \((b - a) \bmod m = 0\) ,即 \(m\) 为 \((b - a)\) 的因子。
推广到 \(n\) 个数同余的情况,可以看作 \(n - 1\) 对相邻的数, \(m\) 同为 \(n - 1\) 对相邻数之差的因子。
所以,问题即转化成了在 \(b_i = |a_{i + 1} - a_i|\) 中寻找 \(gcd \gt 1\) 的最长区间。
可以枚举区间的左端点,然后用双指针或二分结合 \(st\) 表计算区间的右端点。
代码一
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<long long> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
if (n == 1) {
cout << 1 << "\n";
continue;
}
vector<long long> b(n - 1);
for (int i = 0; i < n - 1; i++) {
b[i] = abs(a[i + 1] - a[i]);
}
const int logn = __lg(n) + 1;
vector<vector<long long>> spt(n - 1, vector<long long> (logn));
for (int i = 0; i < n - 1; i++) {
spt[i][0] = b[i];
}
for (int j = 1; j < logn; j++) {
for (int i = 0; i + (1 << j) - 1 < n - 1; i++) {
spt[i][j] = gcd(spt[i][j - 1], spt[i + (1 << (j - 1))][j - 1]);
}
}
auto query = [&](int l, int r) {
int ep = __lg(r - l + 1);
return gcd(spt[l][ep], spt[r - (1 << ep) + 1][ep]);
};
int ans = 0;
for (int i = 0, j = -1; i < n - 1; i++) {
while (j + 1 < n - 1 and query(i, j + 1) > 1) {
++j;
}
if (i <= j) {
ans = max(ans, j - i + 1);
}
j = max(j, i);
}
cout << ans + 1 << "\n";
}
return 0;
}
代码二
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<long long> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
if (n == 1) {
cout << 1 << "\n";
continue;
}
vector<long long> b(n - 1);
for (int i = 0; i < n - 1; i++) {
b[i] = abs(a[i + 1] - a[i]);
}
const int logn = __lg(n) + 1;
vector<vector<long long>> spt(n - 1, vector<long long> (logn));
for (int i = 0; i < n - 1; i++) {
spt[i][0] = b[i];
}
for (int j = 1; j < logn; j++) {
for (int i = 0; i + (1 << j) - 1 < n - 1; i++) {
spt[i][j] = gcd(spt[i][j - 1], spt[i + (1 << (j - 1))][j - 1]);
}
}
auto query = [&](int l, int r) {
int ep = __lg(r - l + 1);
return gcd(spt[l][ep], spt[r - (1 << ep) + 1][ep]);
};
int ans = 0;
for (int i = 0; i < n - 1; i++) {
int l = i, r = n - 2;
while (l < r) {
int mid = (l + r + 1) / 2;
if (query(i, mid) > 1) {
l = mid;
} else {
r = mid - 1;
}
}
if (query(i, r) > 1) {
ans = max(ans, r - i + 1);
}
}
cout << ans + 1 << "\n";
}
return 0;
}