【JZOJ A组】DuLiu

Description

     LF是毒瘤出题人中AK IOI2019,不屑于参加NOI的唯一的人。他对人说话,总是满口垃圾题目者也,教人半懂不懂的。因为他姓李,别人便从QQ群上的“毒瘤李Fee”这半懂不懂的话里,替他取下一个绰号,叫做李Fee。
    李Fee一到机房,所有做题的人便都看着他笑,有的叫道,“李Fee,你又来出毒瘤题了!”他不回答,对验题人说,“我又出了两道题,给我验验。”便排出一排毒瘤题。大家又故意的高声嚷道,“你又暴露奸商本性拿毒瘤题骗钱剥削验题人了!”李Fee睁大眼睛说,“你怎么这样凭空污人清白……”“什么清白?我前天亲眼见你出了道毒瘤骗钱题,被PTY把std吊着打。” 李Fee便涨红了脸,额上的青筋条条绽出,争辩道,“出题人的题不能算骗……毒瘤!……出题人的题,能算毒瘤骗钱题么?”接连便是难懂的话,什么“多叉splay随机点分治”,什么“树链剖分套分治FFT”之类,引得众人都哄笑起来:机房内外充满了快活的空气。

虽然他的题十分毒瘤,但他的题还总是有买家。李Fee现在有N道毒瘤题,想将这些题出成一组题来骗大钱。然而显而易见的是,一组题的毒瘤程度不仅和每道题的毒瘤程度有关,也跟它们的排列顺序有关,李Fee需要将它们排列成最毒瘤但又最能骗钱的那个顺序。
具体来说,这N道题每题都有一个毒瘤值,它们构成了一个序列。李Fee心目中有一个理想的毒瘤值序列,这个序列并不一定每一题的毒瘤值都是原本N道题中出现的,所以李Fee准备进行一些改动。这些改动体现在毒瘤值上就是将某道题的毒瘤值改为所有题的毒瘤值的二进制异或值。但是,改动题目是很麻烦的,他想算出最少需要多少次改动才能将原本的毒瘤值序列改成理想的毒瘤值序列,李Fee忙于出毒瘤题,他想请发明O(1/n)算法用暴力搜过所有毒瘤题的你帮他算出答案。但是他是个奸商,所以他并不打算给你报酬。

Input

第一行1个正整数N,如题目所示。
第二行N个非负整数,表示初始的题目毒瘤值序列
第三行N个非负整数,表示理想的题目毒瘤值序列

Output

单独一行,一个整数,表示最少需要多少次改动
如果怎么改动都无法改成理想的毒瘤值序列,说明这组题出的相当失败,请输出-1

Sample Input

3
0 1 2
3 1 0

Sample Output

2

样例解释:
第一次,整个序列异或为3,把第一个数0换成3,序列变成3,1,2
第二次,整个序列异或为0,把第三个数2换成0,序列变成3,1,0

Data Constraint

对于10%的数据,1<=N<=5
对于30%的数据,1<=N<=10
另有20%的数据,毒瘤值为0或1
对于100%的数据,1<=N<=100000 毒瘤值<2^30

Hint

不要被事物的表面现象所迷惑

思路

事实证明。就算没有被迷惑,你也做不出来

首先,可以发现如果异或值为x,将a[i]替换成x,则x会变成a[i]
所以,我们可以把已获知看成一个元素,每次操作就是交换a[n+1]与a[i]的位置
由此想到构图(将不相等的相连)

可以发现,每一个联通块要交换边数+1次
最后输出ans-1即可(异或值所在联通块不用额外换一次)

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm> 
#include<vector>
#include<map>
using namespace std;
const int N=1e5+77;
vector<int>q[N];
map<int,int>d;
bool vis[N];
int n,a[N],b[N],cnt,ans,x[N],y[N];
void dfs(int x)
{
	vis[x]=1;
	for(int i=0; i<q[x].size(); i++) if(!vis[q[x][i]]) dfs(q[x][i]);
}
int main()
{
	freopen("duliu.in","r",stdin),freopen("duliu.out","w",stdout);
	scanf("%d",&n);
	for(int i=1; i<=n; i++)
	{
		scanf("%d",&a[i]),a[n+1]^=a[i];
		if(!d[a[i]]) d[a[i]]=++cnt;
	}
	if(!d[a[n+1]]) d[a[n+1]]=++cnt;
	for(int i=1; i<=n; i++)
	{
		scanf("%d",&b[i]),b[n+1]^=b[i];
		if(!d[b[i]]) d[b[i]]=++cnt;
	}
	if(!d[b[n+1]]) d[b[n+1]]=++cnt;
	for(int i=1; i<=n+1; i++) x[i]=a[i],y[i]=b[i];
	sort(x+1,x+n+2),sort(y+1,y+n+2);
	for(int i=1; i<=n; i++) if(x[i]!=y[i])
	{
		printf("-1"); return 0;
	}
	for(int i=1; i<=n+1; i++) a[i]=d[a[i]],b[i]=d[b[i]];
	for(int i=1; i<=n; i++) if(a[i]!=b[i]) ans++,q[a[i]].push_back(b[i]);
	if(a[n+1]!=b[n+1]) q[a[n+1]].push_back(b[n+1]);
	for(int i=1; i<cnt; i++) if(q[i].size()&&!vis[i]) dfs(i),ans++;
	if(!vis[cnt]) ans++;
	printf("%d",ans-1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值