• 「题解」CF1468M Similar Sets


    本文将同步发布于:

    题目

    题目链接:洛谷CF1468M

    题意简述

    给定 (n) 个集合 (S_{1sim n}),问是否存在 (i,j) 满足 (i eq j)(leftlvert S_icap S_j ight vertgeq 2)

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

    (nleq 10^5)(sumlimits_{i=1}^nleftlvert S_i ight vertleq 2 imes 10^5)

    题解

    图论转化

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

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

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

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

    那么 (leftlvert S_icap S_j ight vertgeq 2),就对应有至少两个右部点连到了同样的两个点。

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

    并且,这张图的度数总和为 (sumlimits_{i=1}^nleftlvert S_i ight vert)

    按点的度数分治

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

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

    • 找到一个非负整数 (B)
    • 称度数 (geq B) 的为大点,度数 (< B) 的为小点;
    • 对于大点,其个数为 (Thetaleft(frac{sum exttt{deg}}{B} ight))

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

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

    根据上面的分析,我们得出算法的时间复杂度为 (Thetaleft(frac{sum exttt{deg}}{B}sum exttt{deg}+Bsum exttt{deg} ight))

    理论分析可以得出,最优的时间复杂度为 (Thetaleft(sum exttt{deg}sqrt{sum exttt{deg}} ight))

    参考程序

    #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('
    ');
    		else
    			write(ans.first),putchar(' '),write(ans.second),putchar('
    ');
    	}
    	flush();
    	return 0;
    }
    
  • 相关阅读:
    CLASS 类 __getattr__
    class多态
    class类 __repr__ 与__str__
    CLASS类继承
    calss 类
    SVN报错:database is locked
    项目:表格打印(字符图网格进阶、rjust、列表中最长的字符串长度)
    项目:口令保管箱,批处理文件配置.bat
    字典方法 setdefault()、pprint;迭代、递归的区别
    项目:在wiki标记中添加无序列表(split、join巩固)
  • 原文地址:https://www.cnblogs.com/Lu-Anlai/p/14865604.html
Copyright © 2020-2023  润新知