Loading

题解:CF1996G Penacony

CF1996G Penacony

题意

给定一个环,环上有 \(n\) 对点,用最少的边数使每对点都联通。

思路

在环上,两点之间有两种连接方式(如果看做圆上两点,分别是优弧和劣弧)。翻转这个连接(从一个弧至对面的弧)就相当于将其异或,因为异或有如下性质:

\[a \oplus a = 0 \]

所以,对于每一对点,我们对其分别分配一个相同但与其他点对不同的值,并处理异或前缀和,前缀和相同的边就代表拥有同样的连边情况,就可以同时翻转至对面。由于异或值容易重复,例如 \(1 \oplus 2 = 5 \oplus 6\)\(1 \oplus 2 \oplus 3 = 4 \oplus 8 \oplus 12\)。所以我们用随机哈希来避免冲突。保险起见,再加上双哈希。

最终,策略就是删去相同的哈希值的边,我们枚举每个哈希值,统计最多的数量。

代码

#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
int T;
int n,m;
int ans;
pair<int,int> a[200010];
map<pair<int,int>,int>mp;
signed main(){
	srand(time(0));
	cin>>T;
	while(T--){
		memset(a,0,sizeof(a));
		mp.clear();
		ans=0;
		cin>>n>>m;
		for(int i=1;i<=m;i++){
			int x,y;
			cin>>x>>y;
			int r1=666ull*rand()*rand()*rand()+rand()*rand()+rand();//随机生成哈希值
			int r2=114514ull*rand()*rand()*rand()+1919810ull*rand()*rand()+360ull*rand();
			a[x].first^=r1;a[y].first^=r1;
			a[x].second^=r2;a[y].second^=r2;//对两关联点分配同样的哈希值
		}
		for(int i=1;i<=n;i++){
			a[i].first^=a[i-1].first;
			a[i].second^=a[i-1].second;//前缀和
			mp[a[i]]++;//统计一样的哈希值最多的边
		}
		for(map<pair<int,int>,int>::iterator it=mp.begin();it!=mp.end();it++){
			ans=max(ans,it->second);
		}
		cout<<n-ans<<endl;
	}
}
posted @ 2024-10-17 18:31  UserJCY  阅读(27)  评论(0)    收藏  举报
Title