本文将同步发布于:

题目

题目链接:洛谷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)\)。

参考程序

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define reg register
  4. typedef long long ll;
  5. #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  6. static char buf[1<<21],*p1=buf,*p2=buf;
  7. #define flush() (fwrite(wbuf,1,wp1,stdout),wp1=0)
  8. #define putchar(c) (wp1==wp2&&(flush(),0),wbuf[wp1++]=c)
  9. static char wbuf[1<<21];int wp1;const int wp2=1<<21;
  10. inline int read(void){
  11. reg char ch=getchar();
  12. reg int res=0;
  13. while(!isdigit(ch)) ch=getchar();
  14. while(isdigit(ch)) res=10*res+(ch^'0'),ch=getchar();
  15. return res;
  16. }
  17. inline void write(reg int x){
  18. static char buf[32];
  19. reg int p=-1;
  20. if(x<0) x=-x,putchar('-');
  21. if(!x) putchar('0');
  22. else while(x) buf[++p]=(x%10)^'0',x/=10;
  23. while(~p) putchar(buf[p--]);
  24. return;
  25. }
  26. const int MAXN=1e5+5;
  27. const int MAXS=2e5+5;
  28. struct Event{
  29. int x,y,id;
  30. inline Event(reg int x=0,reg int y=0,reg int id=0):x(x),y(y),id(id){
  31. return;
  32. }
  33. };
  34. struct Link{
  35. int val,id;
  36. inline Link(reg int val=0,reg int id=0):val(val),id(id){
  37. return;
  38. }
  39. };
  40. int n;
  41. inline pair<int,int> solve(void){
  42. n=read();
  43. reg int sum=0;
  44. vector<vector<int>> S(n+1);
  45. vector<int> V;
  46. for(reg int i=1;i<=n;++i){
  47. reg int k=read();
  48. sum+=k;
  49. S[i].resize(k);
  50. for(reg int j=0;j<k;++j)
  51. S[i][j]=read(),V.push_back(S[i][j]);
  52. }
  53. sort(V.begin(),V.end()),V.erase(unique(V.begin(),V.end()),V.end());
  54. for(reg int i=1;i<=n;++i)
  55. for(int& x:S[i])
  56. x=lower_bound(V.begin(),V.end(),x)-V.begin();
  57. reg int m=V.size();
  58. reg size_t B=sqrt(sum/16);
  59. vector<int> Big,Sma;
  60. for(int i=1;i<=n;++i)
  61. if(S[i].size()>=B)
  62. Big.push_back(i);
  63. else
  64. Sma.push_back(i);
  65. vector<bool> vis(m);
  66. vis.resize(m);
  67. for(reg int i=0,siz=Big.size();i<siz;++i){
  68. int u=Big[i];
  69. for(int x:S[u])
  70. vis[x]=true;
  71. for(reg int j=1;j<=n;++j){
  72. int v=j;
  73. if(u!=v){
  74. reg int cnt=0;
  75. for(int x:S[v])
  76. if(vis[x])
  77. ++cnt;
  78. if(cnt>=2)
  79. return make_pair(u,v);
  80. }
  81. }
  82. for(int x:S[u])
  83. vis[x]=false;
  84. }
  85. vector<Event> E;
  86. for(reg int i=0,siz=Sma.size();i<siz;++i){
  87. reg int u=Sma[i];
  88. for(reg int j=0,siz=S[u].size();j<siz;++j)
  89. for(reg int k=j+1;k<siz;++k)
  90. E.push_back(Event(S[u][j],S[u][k],u));
  91. }
  92. vector<vector<Link>> G;
  93. G.resize(m);
  94. for(Event e:E)
  95. if(e.x<e.y)
  96. G[e.x].push_back(Link(e.y,e.id));
  97. else
  98. G[e.y].push_back(Link(e.x,e.id));
  99. vector<int> from;
  100. from.resize(m);
  101. for(reg int i=0;i<m;++i){
  102. for(Link L:G[i])
  103. if(!from[L.val])
  104. from[L.val]=L.id;
  105. else
  106. return make_pair(from[L.val],L.id);
  107. for(Link L:G[i])
  108. from[L.val]=0;
  109. }
  110. return make_pair(-1,-1);
  111. }
  112. int main(void){
  113. reg int t=read();
  114. while(t--){
  115. static pair<int,int> ans;
  116. ans=solve();
  117. if(ans.first==-1)
  118. write(-1),putchar('\n');
  119. else
  120. write(ans.first),putchar(' '),write(ans.second),putchar('\n');
  121. }
  122. flush();
  123. return 0;
  124. }

「题解」CF1468M Similar Sets的更多相关文章

  1. 「题解」「美团 CodeM 资格赛」跳格子

    目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞 ...

  2. 「题解」「HNOI2013」切糕

    文章目录 「题解」「HNOI2013」切糕 题目描述 思路分析及代码 题目分析 题解及代码 「题解」「HNOI2013」切糕 题目描述 点这里 思路分析及代码 题目分析 这道题的题目可以说得上是史上最 ...

  3. 「题解」JOIOI 王国

    「题解」JOIOI 王国 题目描述 考场思考 正解 题目描述 点这里 考场思考 因为时间不太够了,直接一上来就着手暴力.但是本人太菜,居然暴力爆 000 ,然后当场自闭- 一气之下,发现对 60pts ...

  4. 「题解」:[loj2763][JOI2013]现代豪宅

    问题 A: 现代豪宅 时间限制: 1 Sec  内存限制: 256 MB 题面 题目描述 (题目译自 $JOI 2013 Final T3$「現代的な屋敷」) 你在某个很大的豪宅里迷路了.这个豪宅由东 ...

  5. 「题解」:$Six$

    问题 A: Six 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 来写一篇正经的题解. 每一个数对于答案的贡献与数本身无关,只与它包含了哪几个质因数有关. 所以考虑二 ...

  6. 「题解」:$Smooth$

    问题 A: Smooth 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 维护一个队列,开15个指针,对应前15个素数. 对于每一次添加数字,暴扫15个指针,将指针对应 ...

  7. 「题解」:Kill

    问题 A: Kill 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 80%算法 赛时并没有想到正解,而是选择了另一种正确性较对的贪心验证. 对于每一个怪,我们定义它的 ...

  8. 「题解」:y

    问题 B: y 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 考虑双向搜索. 定义$cal_{i,j,k}$表示当前已经搜索状态中是否存在长度为i,终点为j,搜索过边 ...

  9. 「题解」:x

    问题 A: x 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 赛时想到了正解并且对拍了很久.对拍没挂,但是评测姬表示我w0了……一脸懵逼. 不难证明,如果对于两个数字 ...

随机推荐

  1. python中实现打印特定字符变换

    首先需要将 lib文件 放在该文件同一目录 使用的时候,先导入 from lib.common import print_msg ,然后调用里面的 print_msg() 方法即可! lib文件地址: ...

  2. 内核模式下的线程同步的分析(Windows核心编程)

    内核模式下的线程同步 内核模式下的线程同步是用户模式下的线程同步的扩展,因为用户模式下的线程同步有一定的局限性.但用户模式下线程同步的好处是速度快,不需要切换到内核模式(需要额外的 CPU 时间).通 ...

  3. 【JavaScript】Leetcode每日一题-青蛙过河

    [JavaScript]Leetcode每日一题-青蛙过河 [题目描述] 一只青蛙想要过河. 假定河流被等分为若干个单元格,并且在每一个单元格内都有可能放有一块石子(也有可能没有). 青蛙可以跳上石子 ...

  4. 解决无法远程登录Docker中的MySQL

    步骤: 进入mysql容器 登录mysql 授予远程登录权限 刷新权限,并退出 命令参考: docker exec -it [mysql] /bin/bash mysql -u root -p ALT ...

  5. JS求一个字符串在另一个字符串中出现的次数

    参数说明: subString子字符串 originString母字符串 isIgnoreCap是否忽略大小写,默认忽略 function stringFre(subString, originStr ...

  6. LVHA爱恨原则

    关于link 和 visited是否访问过,讲得应该是对浏览器而言该网页之前是否访问过, 而不是只对单次生成页面而言

  7. gitlab的CI/CD实现

    环境准备: gitlab账号公网账号:代码仓库和编译器 目标机:装有docker和gitlab-runner环境的服务器(Linux或类unix机器,我使用的时centos 项目代码:testgola ...

  8. Linux ll查看文件属性详解-软硬链接详解

    Linux文件属性及类型 [root@localhost ~]# ll anaconda-ks.cfg 文件类型 权限 硬连接数 文件的大小 文件的创建,修改时间 - rw-------. 1 roo ...

  9. mysql基础之数据库变量(参数)管理

    数据库的数据存放路径:[root@ren7 mysql]# pwd /var/lib/mysql [root@ren7 mysql]# ls aria_log.00000001 ibdata1 mul ...

  10. ZooKeeper学习笔记一:集群搭建

    作者:Grey 原文地址:ZooKeeper学习笔记一:集群搭建 说明 单机版的zk安装和运行参考:https://zookeeper.apache.org/doc/r3.6.3/zookeeperS ...