[AGC016D] XOR Replace 题解

题目链接

点击打开链接

题目解法

很有思维难度的一道题

首先考虑简化操作(或者说用一种比较好的方法表示)
假设我们选择交换的位置为 x,不难发现,操作等价于交换 sumxorx
于是,有解的条件就好判了,即 {bi}{ai}{x}

操作可以理解为路径,即我们将 biai 连边(aibi),需要将每条边的遍历恰好一次(因为这样操作次数最小),
对于连通内的理解是找到一条欧拉路径,根据有解的性质,这个连通块出度和入度的差 1,所以一定有欧拉路径
对于多个连通块,考虑用一条路径将两个连通块串起来
因为对于所有连通块,至多只有一个的出度 入度,且差 1,即说明至多只有一个存在欧拉路径,其他连通块都是存在欧拉回路,这样不难构造出一条合法的路径,使得经过的路径数目为 边数 + 连通块数 - 1

注意特判异或和为孤立点的情况
时间复杂度 O(nlogn)

#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
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);}
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
const int N=200100;
int n,a[N],b[N];
map<int,int> mp;
bool used[N];
int fa[N],siz[N];
int get_father(int x){ return x==fa[x]?x:fa[x]=get_father(fa[x]);}
int main(){
n=read();
int sxor=0;
F(i,1,n) a[i]=read(),mp[a[i]]++,sxor^=a[i];
F(i,1,n) b[i]=read(),mp[b[i]]--;
mp[sxor]++;
for(auto it:mp) if(it.second<0){ puts("-1");exit(0);}
int cnt=0;
for(auto &it:mp) it.second=++cnt;
F(i,1,n) a[i]=mp[a[i]],b[i]=mp[b[i]];sxor=mp[sxor];
F(i,1,cnt) fa[i]=i;
int ans=0;
F(i,1,n) if(a[i]!=b[i]) fa[get_father(b[i])]=get_father(a[i]),ans++,used[a[i]]=used[b[i]]=true;
F(i,1,cnt) if(used[i]) siz[get_father(i)]++;
F(i,1,cnt) ans+=siz[i]>0;
if(!used[sxor]) ans++;
printf("%d\n",max(0,ans-1));
fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
return 0;
}
posted @   Farmer_D  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示