AT_agc059_c 自学式题解
模拟赛 T4,完全没想法,依旧通过写题解进行大学习。
根据题意,建立 \(\frac{n(n-1)}{2}\) 条边的有向图,那么大小关系就是对图上的边进行定向(gemini 说这叫竞赛图)。
显然图应该为 DAG,大小关系不可能出现环。
考虑什么时候会被前面的询问确定:传递性。
比如 \(a<b<c\) 而我们问了 a b, b x 时 a c 会被确定,也就是对图上的点 a,c 存在比边 a c 更早的路径。
那如果路径很长怎么办?根据传递性我们很容易能证明只要三元组不合法整个图都不合法,不再赘述。
考虑三元组,如果边 a,c 没有被确定,那么其他两条边不可以形成路径,比如 \(a\rightarrow b\rightarrow c\) 或者 \(c\rightarrow b\rightarrow a\),也就是说两条边要么同时指向 \(b\) 要么同时背离 \(b\),这就形成了一个 2-sat 问题。
在实现上,我们钦定每个边的初始从大编号指向小编号,而 0/1 状态表示该边是否翻转,然后用扩展域并查集维护边之间的关系,如果有 2-sat 冲突则为 0,否则计数联通块即可。
AC code
#include <bits/stdc++.h>
#define int int64_t
//#define int __int128
#define MOD (1000000007)
//#define eps (1e-6)
#define endl '\n'
#define debug_endl cout<<endl;
#define debug cout<<"debug"<<endl;
using namespace std;
int n,m;
int f[410][410];
int fa[160000];
inline int find(int x){
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
inline void merge(int x,int y){
int fx=find(x),fy=find(y);
if(fx!=fy) fa[fx]=fy;
}
inline int qpow(int a,int b){
int res=1;
while(b){
if(b&1) res=(res*a)%MOD;
a=(a*a)%MOD;
b>>=1;
}
return res;
}
signed main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;
m=n*(n-1)/2;
for(int i=1;i<=m*2;++i){
fa[i]=i;
}
for(int i=1;i<=m;++i){
int x,y;
cin>>x>>y;
if(x<y) swap(x,y);
f[x][y]=i;
}
for(int x=1;x<=n;++x){
for(int y=x+1;y<=n;++y){
for(int z=y+1;z<=n;++z){
pair<int,pair<int,int>> p[3]={{f[y][x],{y,x}},{f[z][y],{z,y}},{f[z][x],{z,x}}};
sort(p,p+3);
int a=p[2].second.first,c=p[2].second.second;
int k=(p[0].second.second==a||p[0].second.second==c)^(p[1].second.second==a||p[1].second.second==c);
if(k==0){
merge(p[0].first,p[1].first);
merge(p[0].first+m,p[1].first+m);
}
else{
merge(p[0].first+m,p[1].first);
merge(p[0].first,p[1].first+m);
}
}
}
}
int cnt=0;
for(int i=1;i<=m;++i){
if(find(i)==find(i+m)) {
cout<<0;
return 0;
}
if(find(i)==i){
++cnt;
}
}
cout<<qpow(2,cnt);
return 0;
}

浙公网安备 33010602011771号