1 条题解
-
0
题目理解
我们有一个数组 ,长度 。
对每个下标 (),可以最多执行一次操作:
将 赋值为 ( 表示按位异或)。
目标:判断是否能将 变成目标数组 。
关键观察
每个位置 的值最多改变一次。
因为操作只允许对每个 最多执行一次,且操作只修改 的值(不修改 )。
因此,在整个过程中:- 要么 保持原来的值
- 要么 在某一时刻被赋值为 (原始值或 取决于操作顺序)
但注意: 也可能被之前的操作改变(如果 位置被操作过)。
所以更准确地说:
当考虑位置 时, 的值可能是原始 ,也可能是 (因为 的操作只可能发生在 之前或之后)。
从后向前贪心
因为操作只影响 ,不影响 ( 只被它自己的操作影响),我们可以从后向前处理。
固定最后一个位置:
永远不会被任何操作修改(因为没有 与其做异或)。
因此 必须 ,否则直接不可能。考虑位置 (从 向下到 ):
我们已知 的最终值就是 (因为后面的已经处理好了)。
现在 的最终值要变成 。
可能的情况:- 没有对 执行操作 必须 。
- 对 执行了操作,此时 变为 。
但 在操作时的值可能是原始值 (如果 还没被操作)或 (如果 已经被操作过)。
所以有两种可能:- 如果 没有在 之前被操作,那么 变成 。
- 如果 在 之前被操作了,那么 变成 。
因此,位置 可行的条件为(三者至少一个成立):
- (不操作)
- (先操作 ,后操作 或不操作 )
- (先操作 ,再操作 )
依赖关系与可行性
这三种情况本质上定义了 和 的操作顺序依赖:
- 如果 ,则 不操作,无依赖。
- 如果 ,则必须 先操作 (若 也会被操作,必须晚于 )。
- 如果 ,则必须 先操作 (若两者都操作,必须早于 )。
注意: 可能被操作,也可能不被操作。
由于所有依赖都是相邻点之间的,这种依赖图一定无环(因为边只会从 指向 或反向)。
因此只要每个 满足至少一个条件,就存在一种全局顺序,使得所有要求满足。
最终算法
- 检查 ,若不等则输出
"NO"。 - 从 向下到 :
- 检查以下三个条件是否至少一个为真:
- 若都不成立,输出
"NO"。
- 检查以下三个条件是否至少一个为真:
- 全部通过则输出
"YES"。
复杂度 每个测试用例。
示例验证
以第一个样例:
检查:, ✓ 通过
检查:, ✓ 通过- ✓ 通过
检查:, ✓ 通过- 结果
"YES"
C++ 实现
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { int n; cin >> n; vector<int> a(n), b(n); for (int i = 0; i < n; i++) cin >> a[i]; for (int i = 0; i < n; i++) cin >> b[i]; bool ok = true; if (a.back() != b.back()) { ok = false; } for (int i = n - 2; i >= 0 && ok; i--) { if (a[i] == b[i]) continue; if ((a[i] ^ a[i + 1]) == b[i]) continue; if ((a[i] ^ b[i + 1]) == b[i]) continue; ok = false; } cout << (ok ? "YES" : "NO") << '\n'; } return 0; }
- 1
信息
- ID
- 7045
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者