JZOJ 5910. 【NOIP2018模拟10.18】DuLiu

题目

给定一个序列,前n-1个元素只能和第n个元素交换。问a序列至少交换多少次变成b序列。

题解

一种贪心的策略:如果a[i]=b[i],那么不交换i位置;离散化之后,a[i]连向b[i]。必然会连成一个个环。
显然,一个个环跑是最优的。
跑完一个环,再去跑另一个环。从一个环跳到另一个环,对答案的贡献为1.
最后一个环只需要跑到最后一个点就行了,无需跑最后一条边。
额外注意,a[n+1]可能独成一个大小为1的环。
必须拍,出多几个小数据。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#define N 100010
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int i,j,k,l,n,m,ans;
int a[N],b[N],c[N],d[N];
int ca,cb,sa,sb,res;
int f[N];
bool bz[N];
int get(int x){
	return f[x]==x?x:f[x]=get(f[x]);
}
void merge(int x,int y){
	int gx=get(x),gy=get(y);
	if(gx^gy)f[gy]=gx;
}
int main(){
	scanf("%d",&n);
	sa=sb=0;
	fo(i,1,n)scanf("%d",&a[i]),c[i]=a[i],sa=sa^a[i];
	fo(i,1,n)scanf("%d",&b[i]),d[i]=b[i],sb=sb^b[i];
	a[n+1]=c[n+1]=sa;
	b[n+1]=d[n+1]=sb;
	sort(c+1,c+n+2);ca=unique(c+1,c+n+2)-c-1;
	sort(d+1,d+n+2);cb=unique(d+1,d+n+2)-d-1;
	if(ca^cb){printf("-1");return 0;}
	fo(i,1,ca)if(c[i]^d[i]){printf("-1");return 0;}
	fo(i,1,n+1)a[i]=lower_bound(c+1,c+ca+1,a[i])-c;
	fo(i,1,n+1)b[i]=lower_bound(d+1,d+cb+1,b[i])-d;
	fo(i,1,n+1)if(a[i]^b[i])f[a[i]]=a[i],f[b[i]]=b[i];
	f[a[n+1]]=a[n+1],f[b[n+1]]=b[n+1];
	fo(i,1,n+1)if(a[i]^b[i]){
		if(i<=n)res++;
		merge(a[i],b[i]);
	}
	fo(i,1,ca){
		f[i]=get(f[i]);
		if(f[i]==i)ans++;
	}
	ans+=res;
	ans=max(ans-1,0);
	printf("%d",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值