【CodeForces】Codeforces Round 625
作者:互联网
比赛链接
官方题解
Problem A. Journey Planning
显然可以枚举 bi 与 i 的差值,并选取所有合法的 bi 。
时间复杂度 O(NLogN) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
map <int, ll> sum;
int main() {
int n; read(n);
for (int i = 1; i <= n; i++) {
int x; read(x);
sum[x - i] += x;
}
ll ans = 0;
for (auto x : sum) {
chkmax(ans, x.second);
}
cout << ans << endl;
return 0;
}
Problem B. Navigation System
考虑将边反向, BFS 求出终点到所有点的最短路。
对于重构次数最小的问题,显然只有在走过一条不是最短路图上的边时需要重构。
对于重构次数最多的问题,若当前点在最短路图上的出边不唯一,则也可以重构。
时间复杂度 O(N+M) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
int n, m, k, q, b[MAXN];
vector <int> a[MAXN];
int dist[MAXN], cnt[MAXN];
void work(int pos) {
static int q[MAXN];
int l = 0, r = 0; q[0] = pos, dist[pos] = 1, cnt[pos] = 1;
while (l <= r) {
int tmp = q[l++];
for (auto x : a[tmp]) {
if (dist[x] == 0) {
dist[x] = dist[tmp] + 1;
q[++r] = x;
}
if (dist[x] == dist[tmp] + 1) {
cnt[x] = min(2, cnt[x] + 1);
}
}
}
}
int main() {
read(n), read(m);
for (int i = 1; i <= m; i++) {
int x, y; read(x), read(y);
a[y].push_back(x);
}
read(q);
for (int i = 1; i <= q; i++)
read(b[i]);
work(b[q]);
int Min = 0, Max = 0;
for (int i = 1; i <= q - 1; i++) {
if (dist[b[i]] != dist[b[i + 1]] + 1) Min++, Max++;
else Max += cnt[b[i]] == 2;
}
cout << Min << ' ' << Max << endl;
return 0;
}
Problem C. World of Darkraft: Battle for Azathoth
从小到大枚举一维坐标,用线段树维护另一维坐标取各个值时的答案。
需要支持区间加,以及维护全局最大值。
时间复杂度 O(NLogN+V) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
const long long INF = 1e18;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
struct SegmentTree {
struct Node {
int lc, rc;
ll tag, Max;
} a[MAXN * 2];
int n, root, size;
void build(int &root, int l, int r) {
root = ++size;
a[root].tag = 0;
a[root].Max = 0;
if (l == r) return;
int mid = (l + r) / 2;
build(a[root].lc, l, mid);
build(a[root].rc, mid + 1, r);
}
void init(int x) {
n = x, root = size = 0;
build(root, 1, n);
}
void update(int root) {
a[root].Max = max(a[a[root].lc].Max, a[a[root].rc].Max);
}
void pushdown(int root) {
if (a[root].tag) {
a[a[root].lc].tag += a[root].tag;
a[a[root].lc].Max += a[root].tag;
a[a[root].rc].tag += a[root].tag;
a[a[root].rc].Max += a[root].tag;
a[root].tag = 0;
}
}
void modify(int root, int l, int r, int ql, int qr, ll d) {
if (l == ql && r == qr) {
a[root].tag += d;
a[root].Max += d;
return;
}
int mid = (l + r) / 2;
pushdown(root);
if (mid >= ql) modify(a[root].lc, l, mid, ql, min(mid, qr), d);
if (mid + 1 <= qr) modify(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, d);
update(root);
}
void modify(int l, int r, ll d) {
modify(root, 1, n, l, r, d);
}
ll query(int root, int l, int r, int ql, int qr) {
if (l == ql && r == qr) return a[root].Max;
int mid = (l + r) / 2; pushdown(root);
if (mid >= qr) return query(a[root].lc, l, mid, ql, qr);
else if (mid + 1 <= ql) return query(a[root].rc, mid + 1, r, ql, qr);
else return max(query(a[root].lc, l, mid, ql, mid), query(a[root].rc, mid + 1, r, mid + 1, qr));
}
ll query(int l, int r) {
if (l > r) return 0;
else return query(root, 1, n, l, r);
}
} ST;
int n, m, p, r; ll x[MAXN], y[MAXN];
vector <pair <int, int>> q[MAXN];
int main() {
read(n), read(m), read(p), r = 1e6;
for (int i = 1; i <= r + 1; i++)
x[i] = y[i] = INF;
for (int i = 1; i <= n; i++) {
int a; ll c; read(a), read(c);
chkmin(x[a], c);
}
for (int i = 1; i <= m; i++) {
int a; ll c; read(a), read(c);
chkmin(y[a], c);
}
for (int i = r; i >= 1; i--) {
chkmin(x[i], x[i + 1]);
chkmin(y[i], y[i + 1]);
}
for (int i = 1; i <= p; i++) {
int a, b, c; read(a), read(b), read(c);
q[a].emplace_back(b, c);
}
ST.init(r);
for (int i = 1; i <= r; i++)
if (y[i] > y[i - 1]) ST.modify(i, r, y[i - 1] - y[i]);
ll ans = -INF;
for (int i = 1; i <= r; i++) {
chkmax(ans, ST.query(1, r) - x[i]);
for (auto x : q[i])
ST.modify(x.first + 1, r, x.second);
}
cout << ans << endl;
return 0;
}
Problem D. Reachable Strings
操作是可逆的,考虑将询问到的字符串归为某个中间状态,再进行比较。一次操作可以看做是将一个 0 向某个方向移动了 2 格,不妨令不能将任何 0 向左移动的状态是中间状态。
那么,不难发现每一段连续的 1 只有奇偶性是重要的。两个字符串 S,T 可以互相到达当且仅当 ∣S∣=∣T∣ ,并且删除所有连续的两个 1 后, S=T 。
由此,设计字符串哈希处理询问即可。
时间复杂度 O(N+Q) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
char s[MAXN]; ull bit[MAXN], h[MAXN];
int n, q, pre[MAXN], sum[MAXN];
int rnk[MAXN], home[MAXN];
ull cal(int x, int cnt) {
return h[x] - h[x - cnt] * bit[cnt];
}
bool cmp(int x, int y, int cnt) {
return cal(rnk[x], cnt) == cal(rnk[y], cnt);
}
int main() {
read(n), bit[0] = 1;
scanf("\n%s", s + 1);
for (int i = 1; i <= n; i++) {
bit[i] = bit[i - 1] * 37;
sum[i] = sum[i - 1] + (s[i] == '0');
pre[i] = pre[i - 1];
if (s[i] == '0') {
pre[i] = i;
rnk[i] = sum[i];
home[sum[i]] = i;
h[sum[i]] = h[sum[i] - 1] * 37;
if ((i - pre[i - 1]) % 2) h[sum[i]] += 5;
else h[sum[i]] += 19;
}
}
read(q);
while (q--) {
int x, y, len;
read(x), read(y), read(len);
x += len - 1, y += len - 1;
if (sum[x] - sum[x - len] != sum[y] - sum[y - len]) puts("No");
else {
int cnt = sum[x] - sum[x - len];
if (cnt == 0) puts("Yes");
else if ((x - pre[x]) % 2 != (y - pre[y]) % 2) puts("No");
else if (cmp(pre[x], pre[y], cnt - 1)) puts("Yes");
else puts("No");
}
}
return 0;
}
Problem E. Treeland and Viruses
将询问涉及到的点取出,建立虚树。
以到达时间为第一关键字,病毒编号为第二关键字,在虚树上运行 Dijkstra 算法即可。
时间复杂度 O(NLogN+∑(M+K)LogN) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
int n; vector <int> a[MAXN];
namespace LowestCommonAncestor {
const int MAXN = 2e5 + 5;
const int MAXLOG = 20;
int depth[MAXN], father[MAXN][MAXLOG];
void work(int pos, int fa) {
depth[pos] = depth[fa] + 1;
father[pos][0] = fa;
for (int i = 1; i < MAXLOG; i++)
father[pos][i] = father[father[pos][i - 1]][i - 1];
for (unsigned i = 0; i < a[pos].size(); i++)
if (a[pos][i] != fa) work(a[pos][i], pos);
}
int lca(int x, int y) {
if (depth[x] < depth[y]) swap(x, y);
for (int i = MAXLOG - 1; i >= 0; i--)
if (depth[father[x][i]] >= depth[y]) x = father[x][i];
if (x == y) return x;
for (int i = MAXLOG - 1; i >= 0; i--)
if (father[x][i] != father[y][i]) {
x = father[x][i];
y = father[y][i];
}
return father[x][0];
}
int climb(int x, int y) {
for (int i = 0; y != 0; i++)
if (y & (1 << i)) {
y ^= 1 << i;
x = father[x][i];
}
return x;
}
}
vector <int> b[MAXN];
int q, m, k, u[MAXN], v[MAXN], s[MAXN];
int points[MAXN], cnt, cmt;
int timer, dfn[MAXN], dist[MAXN], home[MAXN];
void addedge(int x, int y) {
b[x].push_back(y);
b[y].push_back(x);
}
void build() {
static int vis[MAXN], task = 0;
task++, cnt = cmt = 0;
auto mark = [&] (int x) {
if (vis[x] != task) {
vis[x] = task;
points[++cnt] = x;
}
};
mark(1);
for (int i = 1; i <= k; i++)
mark(v[i]);
for (int i = 1; i <= m; i++)
mark(u[i]);
sort(points + 1, points + cnt + 1, [&] (int x, int y) {return dfn[x] < dfn[y];});
int top = 0; cmt = cnt; static int Stack[MAXN];
using namespace LowestCommonAncestor;
for (int i = 1; i <= cnt; i++) {
int x = points[i];
while (top >= 2 && depth[lca(x, Stack[top])] <= depth[Stack[top - 1]]) {
addedge(Stack[top], Stack[top - 1]);
top--;
}
if (top == 0 || lca(x, Stack[top]) == Stack[top]) Stack[++top] = x;
else {
int y = lca(x, Stack[top]);
points[++cmt] = y;
addedge(Stack[top], y);
Stack[top] = y;
Stack[++top] = x;
}
}
while (top >= 2) {
addedge(Stack[top], Stack[top - 1]);
top--;
}
}
void clear() {
for (int i = 1; i <= cmt; i++)
b[points[i]].clear();
}
void dfs(int pos, int fa) {
dfn[pos] = ++timer;
for (auto x : a[pos])
if (x != fa) dfs(x, pos);
}
int path(int x, int y) {
using namespace LowestCommonAncestor; int z = lca(x, y);
return depth[x] + depth[y] - 2 * depth[z];
}
const int INF = 1e9 + 7;
priority_queue <pair <pair <int, int>, int>, vector <pair <pair <int, int>, int>>, greater <pair <pair <int, int>, int>>> Heap;
void cdist() {
static int vis[MAXN], task = 0; task++;
for (int i = 1; i <= cmt; i++) {
dist[points[i]] = INF;
home[points[i]] = 0;
}
for (int i = 1; i <= k; i++) {
dist[v[i]] = 0;
home[v[i]] = i;
Heap.emplace(make_pair(0, i), v[i]);
}
while (!Heap.empty()) {
pair <pair <int, int>, int> tmp = Heap.top(); Heap.pop();
if (vis[tmp.second] == task) continue;
int cur = home[tmp.second];
for (auto x : b[tmp.second])
if (vis[x] != task) {
int len = (path(x, v[cur]) - 1) / s[cur] + 1;
if (len < dist[x] || len == dist[x] && cur < home[x]) {
dist[x] = len, home[x] = cur;
Heap.emplace(make_pair(len, cur), x);
}
}
}
}
int main() {
read(n);
for (int i = 1; i <= n - 1; i++) {
int x, y; read(x), read(y);
a[x].push_back(y);
a[y].push_back(x);
}
LowestCommonAncestor :: work(1, 0);
dfs(1, 0), read(q);
for (int i = 1; i <= q; i++) {
read(k), read(m);
for (int i = 1; i <= k; i++)
read(v[i]), read(s[i]);
for (int i = 1; i <= m; i++)
read(u[i]);
build();
cdist();
for (int i = 1; i <= m; i++)
printf("%d ", home[u[i]]);
printf("\n");
clear();
}
return 0;
}
Problem F. Blocks and Sensors
首先,不考虑方块的颜色,假设范围内所有方块均被填满。
有两类方块是必须拆除的:
(1) 、被颜色 0 照到的方块
(2) 、被两种不同的颜色照到的方块
同时,若不存在这样必须拆除的方块,则或是存在一个有颜色的侦测器所在的直线已经不存在方块,此时答案为 −1 ;或是将所有方块染成所被影响的侦测器的颜色,即可找到一组合法构造。
BFS 实现上述拆除方块的过程即可。
时间复杂度 O(N×M×K) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int dx[6] = {1, -1, 0, 0, 0, 0};
const int dy[6] = {0, 0, 1, -1, 0, 0};
const int dz[6] = {0, 0, 0, 0, 1, -1};
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
int n, m, t, l, r;
int bx[MAXN], by[MAXN], bz[MAXN];
vector <vector <int>> b[6];
vector <vector <vector <int>>> a;
vector <vector <vector <vector <bool>>>> vis;
void Make(vector <vector <int>> &b, int n, int m) {
b.resize(n + 2);
for (int i = 0; i <= n + 1; i++)
b[i].resize(m + 2);
}
bool inside(int x, int y, int z) {
return 1 <= x && x <= n && 1 <= y && y <= m && 1 <= z && z <= t;
}
void add(int x, int y, int z, int d, int v) {
assert(!vis[x][y][z][d]);
vis[x][y][z][d] = true;
if (a[x][y][z] == 0) return;
if (v == 0) {
r++, a[x][y][z] = 0;
bx[r] = x, by[r] = y, bz[r] = z;
} else if (a[x][y][z] == -1 || a[x][y][z] == v) a[x][y][z] = v;
else {
r++, a[x][y][z] = 0;
bx[r] = x, by[r] = y, bz[r] = z;
}
}
int main() {
read(n), read(m), read(t), l = 1;
a.resize(n + 2), vis.resize(n + 2);
for (int i = 0; i <= n + 1; i++) {
a[i].resize(m + 2);
vis[i].resize(m + 2);
for (int j = 0; j <= m + 1; j++) {
a[i][j].resize(t + 2);
vis[i][j].resize(t + 2);
for (int k = 0; k <= t + 1; k++)
vis[i][j][k].resize(6);
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
for (int k = 1; k <= t; k++)
a[i][j][k] = -1;
Make(b[0], m, t);
Make(b[1], m, t);
Make(b[2], n, t);
Make(b[3], n, t);
Make(b[4], n, m);
Make(b[5], n, m);
for (int i = 1; i <= m; i++)
for (int j = 1; j <= t; j++) {
read(b[0][i][j]);
add(1, i, j, 0, b[0][i][j]);
}
for (int i = 1; i <= m; i++)
for (int j = 1; j <= t; j++) {
read(b[1][i][j]);
add(n, i, j, 1, b[1][i][j]);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= t; j++) {
read(b[2][i][j]);
add(i, 1, j, 2, b[2][i][j]);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= t; j++) {
read(b[3][i][j]);
add(i, m, j, 3, b[3][i][j]);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
read(b[4][i][j]);
add(i, j, 1, 4, b[4][i][j]);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
read(b[5][i][j]);
add(i, j, t, 5, b[5][i][j]);
}
while (l <= r) {
for (int i = 0; i <= 5; i++) {
int x = bx[l], y = by[l], z = bz[l], v = 0;
if (i <= 1) v = b[i][y][z];
else if (i <= 3) v = b[i][x][z];
else v = b[i][x][y];
if (vis[x][y][z][i]) {
while (inside(x, y, z) && a[x][y][z] == 0) {
x += dx[i];
y += dy[i];
z += dz[i];
}
if (!inside(x, y, z)) {
if (v != 0) {
puts("-1");
return 0;
}
} else add(x, y, z, i, v);
}
}
l++;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
for (int k = 1; k <= t; k++)
printf("%d ", max(a[i][j][k], 0));
printf("\n");
}
printf("\n");
}
return 0;
}
标签:625,int,void,CodeForces,MAXN,template,root,Round,getchar 来源: https://blog.csdn.net/qq_39972971/article/details/104818172