CF #575 Div3(A-F)

A. Three Piles of Candies

题意:

给三个堆蛋糕,AliceBob 两个人分,要使得两人最后拿到手上的蛋糕数一样多,求两人最多可以获得多少蛋糕。

void solve() { i64 a, b, c; std::cin >> a >> b >> c; std::cout << (a + b + c) / 2 << "\n"; }

B. Odd Sum Segments

题意:

将一个数组分成连续的 k 段,使得每一段内各个数字之和是一个奇数。如果存在这种分法,输出 k 个区间的右端点,否则输出 No

思路:

根据奇数 + 奇数 = 偶数, 偶数 + 偶数 = 偶数奇数 + 偶数 = 奇数可知,要尽可能的让分出的区间数量多,就将每一个奇数分布在不同的区间内,这样奇数和奇数所产生的贡献就不会互相抵消掉。那么判断能不能分出 k 段区间,就是看这个区间内有多少个奇数。现在考虑分法,如果奇数的个数刚好等于 k 那么直接输出就好了;如果奇数个数大于 k ,就要考虑区间合并的问题了,因为 奇数+奇数 = 奇数,所以每一次如果只是两两合并的话,会将两个奇数变成偶数,导致现在这一段不满足条件,所以每一次合并的时候就是三个区间合并成为一个区间,也就相当于是每一次从最后面减掉两个区间,很明显任何一个数减去一个偶数不会改变它本身的奇偶性,所以在判断是否能够分出的时候,还要去考虑奇数的个数的奇偶性是不是和 k 的奇偶性是相同的。

void solve() { int n, m; std::cin >> n >> m; std::vector<int> a(n + 1); i64 ans = 0; std::vector<int> res; for (int i = 1; i <= n; i++) { std::cin >> a[i]; ans += a[i]; if (ans & 1) { res.push_back(i); ans = 0; } } if (int(res.size()) % 2 == m % 2 && res.size() >= m) { std::cout << "Yes\n"; while(res.size() > m) res.pop_back(); res.back() = n; for (int i = 0; i < m; i++) std::cout << res[i] << " \n"[i == m - 1]; } else { std::cout << "No\n"; } }

C.Robot Breakout

题意:

n 个机器人在一个平面上,第 i 个机器人的位置是 (Xi,Yi)。在设计的时候,第 i 个机器人可以执行的操作:

  1. 位置从 (Xi,Yi) 变为 (Xi1,Yi)
  2. 位置从 (Xi,Yi) 变为 (Xi,Yi+1)
  3. 位置从 (Xi,Yi) 变为 (Xi+1,Yi)
  4. 位置从 (Xi,Yi) 变为 (Xi,Yi1)

但设计出现了缺陷,某些机器人可能不能执行上述的某些操作。你需要找一个点 (A,H),使得 n 个机器人都可以到达 (A,H) 。注意,一开始的位置在 (A,H) 也算到达,且对于 A,H 的范围有限制 —— 105A,H105

思路:

对每一个功能进行分析,功能一缺失意味着这个机器人不能向左走,功能二缺失意味着机器人不能向上走,功能三缺失意味着这个机器人不能向右走,功能四缺失意味着这个机器人不能向下走。那么我们就可以根据机器人现在的位置来确定所能够移动的左右边界和上下边界。功能一来确定左边界,功能二来确定上边界,功能三来确定右边界,功能四来确定下边界。

void solve() { int n; std::cin >> n; int x = -1E5, y = -1E5, xx = 1E5, yy = 1E5; for (int i = 0; i < n; i++) { int sx, sy, a, b, c, d; std::cin >> sx >> sy >> a >> b >> c >> d; if (!a) x = std::max(x, sx); if (!b) yy = std::min(yy, sy); if (!c) xx = std::min(xx, sx); if (!d) y = std::max(y, sy); } if (xx < x || yy < y) std::cout << 0 << "\n"; else { std::cout << "1 " << x << " " << y << "\n"; } }

D2.RGB Substring (hard version)

题意:

求修改字符串 s 多少次能够让其中的某一个子串(长度为 k )成为 RGBRGBRGB 的子串。

思路:

D1 的话可以考虑爆力枚举出所有的子串来分别计算修改得次数。 D2 的话就需要去考虑优化的方案了。因为要求一个区间内修改次数的多少,而对于快速求区间和,不难想到用前缀和来优化这个过程。可以考虑用一个目标串 RGB 来计算当前位置需不需要修改,如果需要修改就在上一个位置的基础上加一。

std::string aim = "RGB"; std::vector<std::vector<int>> dp(3, std::vector<int> (n + 1)); for (int i = 0; i < n; i++) for (int j = 0; j < 3; j++) dp[j][i + 1] = dp[j][i] + (s[i] == aim[(i + j) % 3] ? 0 : 1); // 如果匹配上了,就不需要修改,否则修改次数 + 1

最后就是尺取出所有长度为 k 的子串然后计算修改次数

void solve() { int n, k; std::cin >> n >> k; std::string s; std::cin >> s; std::string aim = "RGB"; std::vector<std::vector<int>> dp(3, std::vector<int> (n + 1)); for (int i = 0; i < n; i++) for (int j = 0; j < 3; j++) dp[j][i + 1] = dp[j][i] + (s[i] == aim[(i + j) % 3] ? 0 : 1); int ans = k; for (int i = 0; i <= n - k; i++) for (int j = 0; j <= 2; j++) ans = std::min(ans, dp[j][i + k] - dp[j][i]); std::cout << ans << "\n"; }

E.Connected Component on a Chessboard

题意:

给出一个 109×109 的黑白棋盘( i+j 为奇数的时候是白色,否则为黑色),让我们构造出一个连通块使得黑色的点有 b 个,白色的点有 w 个,并输出构造方案。

思路:

画图可以发现,要想构成一个联通块的话,就必须要让所有的黑白点相邻,而且最优的情况就是尽量使得黑色/白色点的上下左右都选上。那么就考虑将最少的颜色 a 的点放在一条直线上,另一个颜色 b 插空,这样把 a 放置好了,就只需要去考虑将剩下的 b 都放置在 a 的上下方。

void solve() { int b, w; std::cin >> b >> w; bool f = w > b; if (f) std::swap(w, b); std::vector<std::array<int, 2>> res; int x = 2, y = 2; while(w) { res.push_back({x, y}); b -= (y & 1); w -= !(y & 1); y++; } int xx = 1, yy = 2; while(b && yy <= y) { res.push_back({xx, yy}); b--, yy += 2; } int px = 3, py = 2; while(b && py <= y) { res.push_back({px, py}); b--, py += 2; } if (b) res.push_back({2, 1}), b--; if (b) res.push_back({2, y}), b--; if (b) std::cout << "NO\n"; else { std::cout << "YES\n"; for (auto& now : res) std::cout << now[0] << " " << now[1] + f << "\n"; } }

F.K-th Path

题意:

给定一个无向带权连通图,求子节点两两之间路径从小到大排序之后第 k 长的路径长度。

思路:

首先,注意到 k 非常的小,如果只考虑边,那么最多有 k 条边会对答案产生影响,也就是说答案一定小于等于第 k 小的那条边。既然如此,对答案有影响的路径肯定也是由 k 条路径相互组合产生的,那么我们就知道了对答案有影响的点最多只有 k 级别的。那我们就只加前 k 小的边,然后对所有的被加过边的点跑最短路,然后用这个点到其他点的最短路去更新答案

constexpr int N = 200010, M = N * 2; struct node { int v, w, nxt; }e[M]; int idx, n, m, k, cnt; int h[N], a[N]; i64 dist[N]; bool vis[N], st[N]; void add(int a, int b, int c) { e[++idx] = {b, c, h[a]}, h[a] = idx; } struct line { int u, v, w; bool operator< (const line& l) const { return w < l.w; } }edge[N]; void dijkstra(int s) { for (int i = 1; i <= cnt; i++) { dist[a[i]] = 1E18; vis[a[i]] = false; } dist[s] = 0; std::priority_queue<pii, std::vector<pii>, std::greater<pii>> q; q.push({0, s}); while(q.size()) { auto p = q.top(); q.pop(); int u = p.second; if (vis[u]) continue; vis[u] = true; for (int i = h[u]; i; i = e[i].nxt) { int v = e[i].v, w = e[i].w; if (dist[v] > dist[u] + w) { dist[v] = dist[u] + w; if (!vis[v]) q.push({dist[v], v}); } } } } signed main() { std::cin.tie(nullptr)->sync_with_stdio(false); std::cin >> n >> m >> k; for (int i = 1; i <= m; i++) { int u, v, w; std::cin >> u >> v >> w; edge[i] = {u, v, w}; } std::sort(edge + 1, edge + 1 + m); for (int i = 1; i <= std::min(m, k); i++) { add(edge[i].u, edge[i].v, edge[i].w); add(edge[i].v, edge[i].u, edge[i].w); if (!st[edge[i].u]) a[++cnt] = edge[i].u, st[edge[i].u] = true; if (!st[edge[i].v]) a[++cnt] = edge[i].v, st[edge[i].v] = true; } std::priority_queue<i64> q; for (int i = 1; i <= cnt; i++) { dijkstra(a[i]); for (int j = i + 1; j <= cnt; j++) { q.push(-dist[a[j]]); } } for (int i = 1; i < k; i++) q.pop(); std::cout << -q.top() << "\n"; return 0 ^ 0; }

__EOF__

本文作者HoneyGrey
本文链接https://www.cnblogs.com/Haven-/p/16774267.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   浅渊  阅读(54)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示