「题解」CF1468M Similar Sets

Posted Lu_Anlai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「题解」CF1468M Similar Sets相关的知识,希望对你有一定的参考价值。

本文将同步发布于:

题目

题目链接:洛谷CF1468M

题意简述

给定 \\(n\\) 个集合 \\(S_{1\\sim n}\\),问是否存在 \\(i,j\\) 满足 \\(i\\neq j\\)\\(\\left\\lvert S_i\\cap S_j\\right\\rvert\\geq 2\\)

若存在,输出 \\(i,j\\)(任意一对都可);否则输出 \\(-1\\)

\\(n\\leq 10^5\\)\\(\\sum\\limits_{i=1}^n\\left\\lvert S_i\\right\\rvert\\leq 2\\times 10^5\\)

题解

图论转化

直接思考有点难,考虑经典套路,我们把这个问题转化成二分图模型。

对于一个集合 \\(S_i\\),我们将其构造为一个左部点 \\(i\\)

对于一个元素 \\(x\\),我们将其构造为一个右部点 \\(x\\)

如果 \\(x\\in S_i\\),那么图上有一条边 \\((i,x)\\)

那么 \\(\\left\\lvert S_i\\cap S_j\\right\\rvert\\geq 2\\),就对应有至少两个右部点连到了同样的两个点。

换句话说,符合条件的答案对应了图中的一个四元环。

并且,这张图的度数总和为 \\(\\sum\\limits_{i=1}^n\\left\\lvert S_i\\right\\rvert\\)

按点的度数分治

现在我们要解决的问题就是一个二分图内是否存在四元环。

这同样是一个简单的问题,具体地,我们考虑按点的度数分治:

  • 找到一个非负整数 \\(B\\)
  • 称度数 \\(\\geq B\\) 的为大点,度数 \\(< B\\) 的为小点;
  • 对于大点,其个数为 \\(\\Theta\\left(\\frac{\\sum\\texttt{deg}}{B}\\right)\\)

我们对于每个大左部点,标记其所有相连点,如果存在另一个左部点,其连接的标记点个数 \\(\\geq 2\\),那么存在一个四元环。

我们对于每个小左部点,我们枚举其对应的所有的右部点对,然后对于每一个点对,我们枚举其最小值,然后标记其对应点,如果一个点在之前被标记过,那么就存在一个四元环。

根据上面的分析,我们得出算法的时间复杂度为 \\(\\Theta\\left(\\frac{\\sum\\texttt{deg}}{B}\\sum\\texttt{deg}+B\\sum\\texttt{deg}\\right)\\)

理论分析可以得出,最优的时间复杂度为 \\(\\Theta\\left(\\sum\\texttt{deg}\\sqrt{\\sum\\texttt{deg}}\\right)\\)

参考程序

#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
static char buf[1<<21],*p1=buf,*p2=buf;
#define flush() (fwrite(wbuf,1,wp1,stdout),wp1=0)
#define putchar(c) (wp1==wp2&&(flush(),0),wbuf[wp1++]=c)
static char wbuf[1<<21];int wp1;const int wp2=1<<21;
inline int read(void){
	reg char ch=getchar();
	reg int res=0;
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) res=10*res+(ch^\'0\'),ch=getchar();
	return res;
}

inline void write(reg int x){
	static char buf[32];
	reg int p=-1;
	if(x<0) x=-x,putchar(\'-\');
	if(!x) putchar(\'0\');
	else while(x) buf[++p]=(x%10)^\'0\',x/=10;
	while(~p) putchar(buf[p--]);
	return;
}

const int MAXN=1e5+5;
const int MAXS=2e5+5;

struct Event{
	int x,y,id;
	inline Event(reg int x=0,reg int y=0,reg int id=0):x(x),y(y),id(id){
		return;
	}
};

struct Link{
	int val,id;
	inline Link(reg int val=0,reg int id=0):val(val),id(id){
		return;
	}
};

int n;

inline pair<int,int> solve(void){
	n=read();
	reg int sum=0;
	vector<vector<int>> S(n+1);
	vector<int> V;
	for(reg int i=1;i<=n;++i){
		reg int k=read();
		sum+=k;
		S[i].resize(k);
		for(reg int j=0;j<k;++j)
			S[i][j]=read(),V.push_back(S[i][j]);
	}
	sort(V.begin(),V.end()),V.erase(unique(V.begin(),V.end()),V.end());
	for(reg int i=1;i<=n;++i)
		for(int& x:S[i])
			x=lower_bound(V.begin(),V.end(),x)-V.begin();
	reg int m=V.size();
	reg size_t B=sqrt(sum/16);
	vector<int> Big,Sma;
	for(int i=1;i<=n;++i)
		if(S[i].size()>=B)
			Big.push_back(i);
		else
			Sma.push_back(i);
	vector<bool> vis(m);
	vis.resize(m);
	for(reg int i=0,siz=Big.size();i<siz;++i){
		int u=Big[i];
		for(int x:S[u])
			vis[x]=true;
		for(reg int j=1;j<=n;++j){
			int v=j;
			if(u!=v){
				reg int cnt=0;
				for(int x:S[v])
					if(vis[x])
						++cnt;
				if(cnt>=2)
					return make_pair(u,v);
			}
		}
		for(int x:S[u])
			vis[x]=false;
	}
	vector<Event> E;
	for(reg int i=0,siz=Sma.size();i<siz;++i){
		reg int u=Sma[i];
		for(reg int j=0,siz=S[u].size();j<siz;++j)
			for(reg int k=j+1;k<siz;++k)
				E.push_back(Event(S[u][j],S[u][k],u));
	}
	vector<vector<Link>> G;
	G.resize(m);
	for(Event e:E)
		if(e.x<e.y)
			G[e.x].push_back(Link(e.y,e.id));
		else
			G[e.y].push_back(Link(e.x,e.id));
	vector<int> from;
	from.resize(m);
	for(reg int i=0;i<m;++i){
		for(Link L:G[i])
			if(!from[L.val])
				from[L.val]=L.id;
			else
				return make_pair(from[L.val],L.id);
		for(Link L:G[i])
			from[L.val]=0;
	}
	return make_pair(-1,-1);
}

int main(void){
	reg int t=read();
	while(t--){
		static pair<int,int> ans;
		ans=solve();
		if(ans.first==-1)
			write(-1),putchar(\'\\n\');
		else
			write(ans.first),putchar(\' \'),write(ans.second),putchar(\'\\n\');
	}
	flush();
	return 0;
}

以上是关于「题解」CF1468M Similar Sets的主要内容,如果未能解决你的问题,请参考以下文章

cf1080F. Katya and Segments Sets

codeforces#1257 F. Make Them Similar ( 经典中间相遇问题 )

每日cf计划

cf468B Two Sets

CF1042F Leaf Sets

寒假代更新计划