题目链接
题目解法
很有思维难度的一道题
首先考虑简化操作(或者说用一种比较好的方法表示)
假设我们选择交换的位置为 \(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;
}
标签:连通,ch,XOR,int,题解,路径,Replace,read,mp
From: https://www.cnblogs.com/Farmer-djx/p/17910071.html