[AGC016D] XOR Replace 题解
题意:
一个序列 ,一次操作可以将某个位置变成整个序列的异或和。 求最少几步到达目标序列 。
思路:
见到这种题,第一步要去尝试把操作转化。
稍微推一下可以发现,如果 ,则相当于一个 长序列,,每次可以交换 与 ,求最少几次交换使得 等于 。
无解说明又不包含的元素,这个可以直接判断。
考虑最终的答案,肯定是从 的一条路径,所以我们不妨尝试将 视作一条边。
所以我们要找的便是这张图中的一条从 出发的一条最短欧拉路径,如果这张图联通,因为我们现在是已经有解了,所以最短长度等于边数。
如果图不连通,则说明我们需要额外新增一下边使得图联通且存在欧拉路径,假设有 个联通分支,我们先弄 在的那个,然后是第二个,第三个以此类推,每次只需要多增加一条边即可。
假设我们连了 条边,则答案就是 。
为何是最小?首先,对于连通块内部的路径已经是最短的了,其次,将 个连通块变成一个也至少要 条边,所以这个就是最优解。
点击查看代码
#include <iostream>
#include <vector>
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;
int n, a[N] = {0}, b[N] = {0};
map<int, int> mp;
vector<int> e[N];
bool vis[N] = {false};
void dfs(int x) {
vis[x] = true;
for (auto i: e[x])
if (!vis[i])
dfs(i);
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i], mp[a[i]]++, a[0] ^= a[i];
for (int j = 1; j <= n; j++)
cin >> b[j], mp[b[j]]--;
mp[a[0]]++;
for (auto i: mp)
if (i.second < 0) {
cout << -1;
return 0;
}
int cur = 0;
for (auto &i: mp)
i.second = ++cur;
a[0] = mp[a[0]];
int ed = 0;
for (int i = 1; i <= n; i++) {
a[i] = mp[a[i]];
b[i] = mp[b[i]];
if (a[i] != b[i]) {
e[b[i]].push_back(a[i]);
e[a[i]].push_back(b[i]);
ed++;
}
}
int cnt = 0;
for (int i = 1; i <= cur; i++)
if (!vis[i] && (int)e[i].size() > 0)
dfs(i), ++cnt;
if ((int)e[a[0]].size() > 0)
cnt--;
cout << ed + cnt << endl;
return 0;
}
分类:
图论 / 欧拉路径/欧拉回路
, 图论 / 构图
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通