[AGC016D] XOR Replace 题解

发布时间 2023-12-17 23:03:32作者: Farmer_D

题目链接

点击打开链接

题目解法

很有思维难度的一道题

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

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

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

#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;
}