JZOJ5910. 【NOIP2018模拟10.18】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)算法用暴力搜过所有毒瘤题的你帮他算出答案。但是他是个奸商,所以他并不打算给你报酬。

Data Constraint

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

题解

可以知道,一个序列,无论怎么样变化,只有n+1个元素。
于是就可以很轻松地处理掉不合法的情况。
至于求最小次数,可以用并查集,
在同一个并查集里面的点全部交换就是并查集大小的,
如果要跨过并查集交换,次数就要+1.

code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define N 100003
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
	n=0;
	ch=G();
	while((ch<'0' || ch>'9') && ch!='-')ch=G();
	int w=1;
	if(ch=='-')w=-1,ch=G();
	while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
	n*=w;
}

int a[N],b[N],f[N],g[N],h[N],t[N],n,ans;

int get(int x){return f[x]=(f[x]==x?x:get(f[x]));}

int main()
{
	freopen("duliu.in","r",stdin);
	freopen("duliu.out","w",stdout);
	
	read(n);
	for(int i=1;i<=n;i++)read(a[i]),a[n+1]=a[n+1]^a[i];
	for(int i=1;i<=n;i++)read(b[i]),b[n+1]=b[n+1]^b[i];
	memcpy(h,a,sizeof(h));
	memcpy(t,b,sizeof(t));
	sort(h+1,h+n+2);sort(t+1,t+n+2);
	for(int i=1;i<=n+1;i++)
	{
		f[i]=i;g[i]=1;
		a[i]=lower_bound(h+1,h+n+1,a[i])-h;
		b[i]=lower_bound(h+1,h+n+1,b[i])-h;
		if(t[i]^h[i])
		{
			puts("-1");
			return 0;
		}
	}
	
	for(int i=1;i<=n+1;i++)
		if(a[i]^b[i])
		{
			ans++;
			g[get(b[i])]+=g[get(a[i])];
			f[get(a[i])]=get(b[i]);
		}
	if(a[n+1]^b[n+1])ans--;
	for(int i=1;i<=n+1;i++)if(f[i]==i && g[i]>1)ans++;
	if(g[get(a[n+1])]>1)ans--;
	printf("%d",ans);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lijf2001/article/details/83240133