P8252 [NOI Online 2022 提高组] 讨论 题解
unputdownable · · 题解
文中
文中所有
首先考虑一个暴力:
对于每一个题目
i ,找出会i 这道题的所有人,将其按会的题目数k_x 从小到大排序。然后我们检查上述排序后相邻的两个人是否会讨论即可。
这个暴力的正确性证明:
因为每次被排序的人都至少会同一道题
i ,所以只要考虑是否完全包含即可。假设
x,y,z 三个人会同一题i 并且k_x \leq k_y \leq k_z ,那么如果x,y 和y,z 间都不会讨论,那么必然有S_x \subseteq S_y \subseteq S_z ,那么x,z 也必然不会讨论。
考虑优化上述暴力。
首先将所有人按
如果我们对于每一道题
但是这样由于每一个
随后我们发现,在遍历
这样每次插入一个人的时间复杂度变为
总体复杂度
Code:
int n;
int k[1000006],a[1000006];
vector <int> p[1000006];
int cnt[1000006];
inline void clear(vector <int> X) {
vector <int> e;
e.swap(X);
}
inline bool cmp(int x,int y) {
return k[x]<k[y];
}
int vis[1000006];
inline void work() {
for(int i=1; i<=n; ++i) vis[i]=0;
for(int i=1; i<=n; ++i) cnt[i]=0;
n=read();
for(int i=1; i<=n; ++i) {
k[i]=read();
clear(p[i]);
p[i].resize(k[i]);
for(int u=0; u<k[i]; ++u) p[i][u]=read();
a[i]=i;
}
sort(a+1,a+n+1,cmp);
for(int t=1; t<=n; ++t) {
int i=a[t];
if(k[i]==0) continue;
for(int u=0; u<k[i]; ++u) {
++cnt[vis[p[i][u]]];
}
for(int u=0; u<k[i]; ++u) {
int g=vis[p[i][u]];
if(g!=0&&cnt[g]<k[g]&&cnt[g]<k[i]) {
puts("YES");
write(i); putchar(' '); write(g); puts("");
return ;
}
}
for(int u=0; u<k[i]; ++u) {
--cnt[vis[p[i][u]]];
vis[p[i][u]]=i;
}
}
puts("NO");
}