讨论 题解
simple_dream · · 题解
看到这道题有一个显然的想法,就是先将集合按大小从小到大排序。然后遍历每个集合,每个集合都塞进集合中每个元素所对应的桶。显然一个桶中的所有集合都包含着这个桶所对应的元素,之后只需要判断一个桶中是否有互相不包含的两个集合即可。
记一个桶中的集合分别是
但是这里会出现一个问题。由于一个集合被塞进了很多个桶里面,所以一个集合最多可能会判断
这个的复杂度是
代码如下
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
const int Mod1 = 1e7 + 7;
const int Mod2 = 1e7 + 9;
int t;
int n;
bool mp1[Mod1],mp2[Mod2];
void Hash(long long val)
{
mp1[val % Mod1] = 1;
mp2[val % Mod2] = 1;
}
bool in_hash(long long val)
{
return mp1[val % Mod1] && mp2[val % Mod2];
}
struct node
{
int k,id;
vector<int> ve;
void clear()
{
k = 0;
ve.clear();
}
}a[N];
vector<int> ve[N];
bool cmp(const node &x,const node &y)
{
return x.k < y.k;
}
bool check(const node &x,const node &y)
{
int i = 0,j = 0;
while(i < x.k)
{
if(x.ve[i] == y.ve[j])
{
i++;
}
else
{
j++;
if(j >= y.k)
{
return 1;
}
}
}
return 0;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(mp1,0,sizeof(mp1));
memset(mp2,0,sizeof(mp2));
for(int i = 1;i <= n;i++)
{
a[i].clear();
ve[i].clear();
scanf("%d",&a[i].k);
a[i].id = i;
bool flag = 0;
for(int j = 1;j <= a[i].k;j++)
{
int val;
scanf("%d",&val);
a[i].ve.push_back(val);
}
for(int j = 1;j < a[i].k;j++)
{
if(a[i].ve[j] < a[i].ve[j - 1])
{
flag = 0;
break;
}
}
if(!flag) sort(a[i].ve.begin(),a[i].ve.end());
}
sort(a + 1,a + n + 1,cmp);
for(int i = 1;i <= n;i++)
{
for(int j = 0;j < a[i].k;j++)
{
ve[a[i].ve[j]].push_back(i);
}
}
int ans1 = 0,ans2 = 0;
for(int i = 1;i <= n;i++)
{
int len = ve[i].size();
len--;
for(int j = 0;j < len;j++)
{
long long x = 1ll * ve[i][j] * N + ve[i][j + 1];
if(in_hash(x))
{
continue;
}
Hash(x);
if(check(a[ve[i][j]],a[ve[i][j + 1]]))
{
ans1 = ve[i][j];
ans2 = ve[i][j + 1];
break;
}
}
if(ans1)
{
break;
}
}
if(ans1)
{
printf("YES\n%d %d\n",a[ans1].id,a[ans2].id);
}
else
{
printf("NO\n");
}
}
return 0;
}