【CodeForces】Codeforces Round 625

比赛链接

点击打开链接

官方题解

点击打开链接

Problem A. Journey Planning

显然可以枚举 b i b_i i i 的差值,并选取所有合法的 b i b_i

时间复杂度 O ( N L o g N ) 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 ) 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 ( N L o g N + V ) 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 0 向某个方向移动了 2 2 格,不妨令不能将任何 0 0 向左移动的状态是中间状态。

那么,不难发现每一段连续的 1 1 只有奇偶性是重要的。两个字符串 S , T S,T 可以互相到达当且仅当 S = T |S|=|T| ,并且删除所有连续的两个 1 1 后, S = T S=T

由此,设计字符串哈希处理询问即可。

时间复杂度 O ( N + Q ) 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 ( N L o g N + ( M + K ) L o g N ) O(NLogN+\sum(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 ) (1) 、被颜色 0 0 照到的方块
( 2 ) (2) 、被两种不同的颜色照到的方块

同时,若不存在这样必须拆除的方块,则或是存在一个有颜色的侦测器所在的直线已经不存在方块,此时答案为 1 -1 ;或是将所有方块染成所被影响的侦测器的颜色,即可找到一组合法构造。

BFS 实现上述拆除方块的过程即可。

时间复杂度 O ( N × M × K ) O(N\times M\times 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;
}
发布了813 篇原创文章 · 获赞 93 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/104818172