CF1468M Similar Sets

题目大意

你有 $n$ 个序列,每个序列里有一些元素。每个序列中的元素互不相同,但不同序列中的元素可以相同。

定义两个序列 $A, B$ 是相似的,如果存在两个不同的整数 $x, y$ ,满足 $x, y \in A, x, y \in B$。

现在你要找出任意一对相似的序列,或者输出无解。

$1 \leq n, \sum k_i \leq 10^5$,其中 $k_i$ 表示第 $i$ 个序列的元素个数

题目分析

直接做不太好做,我们考虑根号分治。设 $m$ 表示 $\sum k_i$,考虑到 $m,n$ 在同一数量级,我们下文复杂度分析中的 $m$ 统一用 $n$ 代替。

首先我们考虑那些大小超过 $\sqrt n$ 的序列,枚举每一个大小超过 $\sqrt n$ 的序列。

考虑用一个桶存下这个序列中的所有元素,接着我们枚举所有其他序列,并检查有没有任何一个序列和当前序列有两个以上的数重复。

如果我们在一开始做一个离散化的话,每次操作的时空复杂度就是 $ \Theta (n)$ 的,考虑到最多有 $ \sqrt n $ 个这样的序列,这部分的时间复杂度为 $ n \sqrt n$ 。

然后我们再考虑那些大小小于 $ \sqrt m$ 的所有序列。枚举所有这些数列的所有元素对 $(x, y)$ ,并把它们存储下来。容易发现这样的元素对有

$ \sum_{k_i < \sqrt n} \frac{k_i \times (k_i - 1)}{2}$ 个,根据均值不等式知道总共有 $ \Theta (n \sqrt n)$ 个这样的数对,并且我们可以用 $n$ 个 $\texttt{vector}$ 在 $ \Theta (n \sqrt n)$ 的时间里检查是否有两对相同数对。

这样我们就有了一个对所有情况都有效的算法,总时间复杂度 $ \Theta (n \sqrt n)$。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>

#define R register
#define ll long long
#define pair std::pair<int, int>
#define mp(i, j) std::make_pair(i, j)
#define sum(a, b, mod) (((a) + (b)) % mod)
#define meow(cat...) fprintf(stderr, cat)

const int MaxN = 2e5 + 10;

int n, m, cnt, vis[MaxN];
std::vector<int> v, b, a[MaxN];
std::vector<pair> vec[MaxN];

void init()
{
v.clear(), b.clear();
memset(vis, 0, 4 * (m + 10));
for (int i = 1; i <= n; i++)
a[i].resize(1);
}

inline int read()
{
int x = 0;
char ch = getchar();
while (ch > '9' || ch < '0')
ch = getchar();
while (ch <= '9' && ch >= '0')
x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return x;
}

signed main()
{
int T = read();
while (T--)
{
int flag = 0;
n = read(), init();
for (int i = 1; i <= n; i++)
{
a[i][0] = read(), m += a[i][0], a[i].resize(a[i][0] + 1);
for (int j = 1; j <= a[i][0]; j++)
a[i][j] = read(), b.push_back(a[i][j]);
std::sort(++a[i].begin(), a[i].end());
}
m = sqrt(m) / 2, std::sort(b.begin(), b.end());
b.erase(std::unique(b.begin(), b.end()), b.end());
for (int i = 1; i <= n; i++)
for (int j = 1; j <= a[i][0]; j++)
a[i][j] = std::lower_bound(b.begin(), b.end(), a[i][j]) - b.begin() + 1;
// meow("%d%c", a[i][j], " \n"[j == a[i][0]]);
for (int i = 1; i <= n; i++)
{
if (a[i][0] > m)
{
cnt = 0;
memset(vis, 0, 4 * (b.size() + 10));
for (int j = 1; j <= a[i][0]; j++)
vis[a[i][j]] = 1;
for (int j = 1; j <= n; j++)
if (i ^ j)
{
cnt = 0;
for (int k = 1; k <= a[j][0]; k++)
{
vis[a[j][k]]++, cnt += (vis[a[j][k]] == 2);
if (cnt == 2 && !flag)
{
flag = 1, printf("%d %d\n", i, j);
break;
}
}
for (int k = 1; k <= a[j][0]; k++)
vis[a[j][k]]--;
if (flag) break;
}
}
else
v.push_back(i);
}
memset(vis, 0, 4 * (b.size() + 10));
for(int i = 1; i <= b.size(); i++)
vec[i].clear();
for(auto i : v)
{
for(int j = 1; j <= a[i][0]; j++)
for(int k = j + 1; k <= a[i][0]; k++)
vec[a[i][j]].push_back(mp(a[i][k], i));
}
for(int i = 1; i <= b.size(); i++)
{
for(int j = 0; j < vec[i].size(); j++)
{
if(vis[vec[i][j].first] && !flag)
{
printf("%d %d\n", vis[vec[i][j].first], vec[i][j].second);
flag = 1; break;
}
vis[vec[i][j].first] = vec[i][j].second;
}
if(flag) break;
for (int j = 0; j < vec[i].size(); j++)
vis[vec[i][j].first] = 0;
}
if(!flag) puts("-1");
}
return 0;
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×