「题解」Codeforces Round 895 (Div. 3)
A. Two Vessels
Problem
Sol & Code
签到题
#include <bits/stdc++.h>
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int T, a, b, c;
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d %d %d", &a, &b, &c);
double res = std::abs(b - a) / 2.0;
printf("%d\n", (int)std::ceil(res / c));
}
return 0;
}
B. The Corridor or There and Back Again
Problem
Sol & Code
对于每个陷阱(不考虑其他陷阱)求最多能平安到达的位置,最后对每个陷阱取最小值。
#include <bits/stdc++.h>
#define N 101
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int T, n, a[N];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1, x, y; i <= n; ++i) {
scanf("%d %d", &x, &y);
a[i] = x + (int)std::floor((y - 1) / 2.0);
}
int ans = 114514;
for (int i = n; i >= 1; --i) ans = min(ans, a[i]);
printf("%d\n", ans);
}
return 0;
}
C. Non-coprime Split
Problem
Sol & Code
考虑 \([l,r]\) 这个区间的长度。若长度为 \(2\),\(l,r\) 一奇一偶,讨论可知 \([1,2],[2,3]\) 无解,其他情况答案可为将 \(l,r\) 中偶数分为两半。
若长度为 \(3\),讨论可知 \([1,3]\) 无解,有解的情况答案容易得出不再详细说。长度大于 \(3\) 肯定有解,答案也容易得出。若长度为 \(1\),考虑是 \(a+b =l\) 的情况,若 \(gcd(a,b) = 1\) 说明\(a,b\) 无公共质因数,可以根据算数基本定理可知不存在整除 \(l\) 且小于 \(l\) 的质数故 \(l\) 为质数,有解的情况即 \(l\) 不为质数,找个公共的质因子 \(p\),令 \(a = p,b = l - p\) 即可。
#include <bits/stdc++.h>
#define N 10000001
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
bool vis[N];
int T, l, r, cnt, pri[N];
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
void getprime() {
for (int i = 2; i < N; ++i) {
if (!vis[i]) pri[++cnt] = i;
for (int j = 1; j <= cnt; ++j) {
if (1ll * i * pri[j] >= N) break;
vis[i * pri[j]] = true;
if (i % pri[j] == 0) break;
}
}
}
int main() {
scanf("%d", &T);
getprime();
while (T--) {
scanf("%d %d", &l, &r);
if (r - l + 1 == 3) {
if (l == 1) puts("-1");
else {
if (l & 1) printf("%d %d\n", (l + 1) / 2, (l + 1) / 2);
else printf("%d %d\n", (l + 2) / 2, (l + 2) / 2);
}
} else if (r - l + 1 == 2) {
if (l == 1 || l == 2) puts("-1");
else {
if (l & 1) printf("%d %d\n", (l + 1) / 2, (l + 1) / 2);
else printf("%d %d\n", l / 2, l / 2);
}
} else if (l == r) {
if (l & 1) {
if (vis[l]) {
int prt = 0;
for (int i = 1; i <= cnt; ++i) {
if (l % pri[i] == 0) {
if ((l / pri[i]) & 1) { prt = pri[i]; break; }
}
}
if (!prt) puts("-1");
else printf("%d %d\n", prt, l - prt);
} else puts("-1");
} else {
if (l != 2) printf("%d %d\n", l / 2, l / 2);
else puts("-1");
}
} else {
if (r & 1) printf("%d %d\n", (r - 1) / 2, (r - 1) / 2);
else printf("%d %d\n", r / 2, r / 2);
}
}
return 0;
}
D. Plus Minus Permutation
Problem
Sol & Code
根据题意可知 \(x\) 的贡献有 \(\lfloor \dfrac{n}{x}\rfloor\) 个数记作 \(a\),\(y\) 的贡献有 \(\lfloor \dfrac{n}{x}\rfloor\) 个数记作 \(b\),其中两者共同的贡献有 \(\lfloor \dfrac{n}{\operatorname{lcm}(x,y)}\rfloor\)(其中 \(\operatorname{lcm}(x,y)\) 为 \(x,y\) 的最小公倍数)个数记作 \(c\)。
所以答案为 \(n + (n - 1) + \dots + [n - (a - c) + 1] - [1 + 2 + \dots + (b - c)]\)。
#include <bits/stdc++.h>
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int T;
ll n, x, y;
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
ll lcm(ll a, ll b) { return a / gcd(a, b) * b; }
int main() {
scanf("%d", &T);
while (T--) {
scanf("%lld %lld %lld", &n, &x, &y);
ll num1 = n / x - n / lcm(x, y), num2 = n / y - n / lcm(x, y);
printf("%lld\n", (n + n - num1 + 1) * num1 / 2 - (1 + num2) * num2 / 2);
}
return 0;
}
E. Data Structures Fan
Problem
Sol & Code
线段树可做
#include <bits/stdc++.h>
#define N 100001
#define lson now << 1
#define rson now << 1 | 1
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
std::string s;
int T, n, q, w[N];
struct Node {
int l, r, xor0, xor1, lazy;
}t[N << 2];
void build(int l, int r, int now) {
t[now].l = l, t[now].r = r, t[now].xor0 = 0, t[now].xor1 = 0, t[now].lazy = 0;
if (l == r) {
if (s[l - 1] == '0') t[now].xor0 = w[l];
else t[now].xor1 = w[l];
return;
}
int mid = (l + r) >> 1;
build(l, mid, lson), build(mid + 1, r, rson);
t[now].xor0 = t[lson].xor0 ^ t[rson].xor0;
t[now].xor1 = t[lson].xor1 ^ t[rson].xor1;
}
void pushdown(int now) {
if (t[now].l == t[now].r) return;
t[lson].lazy ^= 1, t[rson].lazy ^= 1;
int tmp1 = t[lson].xor0, tmp2 = t[rson].xor0;
t[lson].xor0 = t[lson].xor1, t[lson].xor1 = tmp1;
t[rson].xor0 = t[rson].xor1, t[rson].xor1 = tmp2;
t[now].lazy = 0;
}
void fix(int x, int y, int now) {
if (t[now].l >= x && t[now].r <= y) {
t[now].lazy ^= 1;
int tmp = t[now].xor0;
t[now].xor0 = t[now].xor1;
t[now].xor1 = tmp;
return ;
}
if (t[now].lazy) pushdown(now);
int mid = (t[now].l + t[now].r) >> 1;
if (x <= mid) fix(x, y, lson);
if (y > mid) fix(x, y, rson);
t[now].xor0 = t[lson].xor0 ^ t[rson].xor0;
t[now].xor1 = t[lson].xor1 ^ t[rson].xor1;
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &w[i]);
std::cin >> s;
build(1, n, 1);
scanf("%d", &q);
for (int i = 1, opt, x, y; i <= q; ++i) {
scanf("%d %d", &opt, &x);
if (opt == 1) {
scanf("%d", &y);
fix(x, y, 1);
} else printf("%d ", x ? t[1].xor1 : t[1].xor0);
}
puts("");
}
return 0;
}
F. Selling a Menagerie
Problem
sol&Code
如果 \(a\) 害怕 \(b\) 则由 \(a\) 向 \(b\) 连边。之后拓扑序 \(dp\) 可解。
#include <bits/stdc++.h>
#define N 100001
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int T, n, c[N], f[N], rd[N];
int head = 1, tail, q[N];
void solve(int u) {
int minn = c[u], flag = u, now = f[u];
while (now != u) {
if (c[now] < minn) {
minn = c[now];
flag = now;
}
now = f[now];
}
now = f[flag];
while (now !=flag) {
--rd[now];
printf("%d ", now);
now = f[now];
}
--rd[now];
printf("%d ", now);
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &f[i]);
++rd[f[i]];
}
head = 1, tail = 0;
for (int i = 1; i <= n; ++i) {
if (rd[i] == 0) q[++tail] = i;
scanf("%d", &c[i]);
}
while (head <= tail) {
int tp = q[head++];
--rd[f[tp]];
if (rd[f[tp]] == 0) q[++tail] = f[tp];
printf("%d ", tp);
}
for (int i = 1; i <= n; ++i) {
if (rd[i] != 0) solve(i);
}
puts("");
}
return 0;
}
G. Replace With Product
Problem
Sol & Code
全部加和的最大值 \(max = 200000000000000\)。
用这个最大值除以非 \(1\) 的数,如果小于等于 \(1\) 了就说明乘积的贡献非常大,就将除去两侧 \(1\) 的部分做乘积。
\(max\) 约为 \(2^{48}\) 说明不符合上述情况的数列,非 \(1\) 的数最多 \(47\) 个。
用 \(47^2\) 的时间枚举左右边界取最大即可。
枚举
#include <bits/stdc++.h>
#define N 200001
int T, n, cnt, a[N], p[N];
long long premul[N], presum[N];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
premul[0] = 1, presum[0] = 0, cnt = 0;
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
if (a[i] > 1) p[++cnt] = i;
premul[i] = premul[i - 1] * a[i];
presum[i] = presum[i - 1] + a[i];
}
bool okay = false;
double now = 200000000000000;
for (int i = 1; i <= cnt; ++i) {
now /= a[p[i]] * 1.0;
if (now <= 1.0) okay = true;
}
if (cnt >= 48 || okay) {
int l = 0, r = 0;
for (int i = 1; i <= n; ++i) {
if (a[i] != 1) { l = i; break; }
}
for (int i = n; i; --i) {
if (a[i] != 1) { r = i; break; }
}
printf("%d %d\n", l, r);
} else {
long long maxx = presum[n], l = 1, r = 1;
for (int i = 1; i <= cnt; ++i) {
for (int j = i; j <= cnt; ++j) {
if (presum[n] - presum[p[j]] + presum[p[i] - 1] + premul[p[j]] / premul[p[i] - 1] > maxx) {
maxx = presum[n] - presum[p[j]] + presum[p[i] - 1] + premul[p[j]] / premul[p[i] - 1];
l = p[i], r = p[j];
}
}
}
printf("%lld %lld\n", l, r);
}
}
return 0;
}
总结
C. 分类讨论好像复杂了。
E. 现在是只会暴力数据结构的 fw 了(甚至数据结构都不会),异或前缀和。