CF1687C Sanae and Giant Robot 题解

题目链接:https://codeforces.com/contest/1687/problem/C

题意简述

有两个长为 n 的数列 ab。有 m 条线段,你可以进行任意次以下操作:

  • 选择一条线段 [l,r],若 i=lrai=i=lrbi,将 a[l,r] 段置为 b

问是否能使 ab 相同。

题解

这题其实非常简单。首先要转化问题。令两数组差的前缀和 sn=i=1n(aibi),则操作等价于:

  • sl1=sr,将 s[l1,r] 段置为 sr

问题等价于能否使 s 变为全 0

这时问题已经很清晰了,我们倒序考虑操作,不难得到如下结论:

  • 一次 sl1=sr0 的操作是毫无意义的,也就是操作总有 sl1=sr=0

  • 那么,既然所有操作都要端点为 0 时才能操作,且最终的目标也是全 0,只要一次操作可以进行,立即进行总是最优的。且已经执行该操作后,不会需要再次执行。

考虑如何模拟这个过程。我们很容易想到类似拓扑排序的模型,将每条线段置为 0 时,对每个被置为 0 的点,判断其出边对应的操作是否可以执行了即可。进行所有操作后,判断 s 数组是否已经为全 0 即可。

每个点只会被置零一次。可以使用 set 维护尚未被置零的点,或者使用并查集甚至链表等其他手段保证正确复杂度。时间复杂度 O(nlogn+m)O(nα(n)+m)O(n+m)

代码实现

我练习写了一版并查集,但再想想用 set 会方便简洁许多,因此在这里附上更短的代码。

#define int i64
void solve() {
int n, m;
cin >> n >> m;
vector<int> a(n + 1), b(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) cin >> b[i];
vector<int> s(n + 1);
for (int i = 1; i <= n; i++) { s[i] = s[i - 1] + a[i] - b[i]; }
vector<pair<int, int>> op;
queue<int> q;
vector<vector<int>> adj(n + 1);
set<int> nz;
for (int i = 1; i <= n; i++) {
if (s[i]) nz.insert(i);
}
for (int i = 0; i < m; i++) {
int l, r;
cin >> l >> r;
l--;
op.push_back({l, r});
if (!s[l] && !s[r]) { q.push(i); }
if (s[l]) adj[l].push_back(i);
if (s[r]) adj[r].push_back(i);
}
while (q.size()) {
int id = q.front();
q.pop();
auto [l, r] = op[id];
for (auto it = nz.lower_bound(l); it != nz.end() && *it <= r;
it = nz.erase(it)) {
int x = *it;
s[x] = 0;
for (int u : adj[x]) {
auto [l, r] = op[u];
if (!s[l] && !s[r]) q.push(u);
}
}
}
if (ranges::count(s, 0) != (i64)s.size()) cout << "No\n";
else cout << "Yes\n";
}
#undef int
posted @   cccpchenpi  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示