1. 程式人生 > >JZOJ5910. 【NOIP2018模擬10.18】DuLiu

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