Atcoder
题解
]
ARC197D 祖孙关系题解
如果 $a_{x,y}=1$,那么 $x,y$ 具有祖先关系,我们发现儿子的所有祖先关系都被他祖先包括了,因此 $a_x | a_y=a_x$ 或 $a_x | a_y=a_y$。 |
我们不妨把所有节点 $i$ 按照 $a_i$ 中 $1$ 的数量进行排序,那么 $1$ 越多的深度肯定越大。也就是说,我们不妨对于每个节点 $i$ 找到最深的,深度比 $i$ 小的点 $j$ 满足 $a_{i,j}=1$ 的点,然后将 $i$ 的父亲设置为 $j$。
根据父亲关系建树,判断是否可行。
如果有 $p$ 个非一点完全相同,对答案的贡献就是 $p!$。
#include<bits/stdc++.h>
#define siz(x) int((x).size())
#define all(x) std::begin(x),std::end(x)
#define fi first
#define se second
using namespace std;
using unt=unsigned;
using loli=long long;
using lolu=unsigned long long;
using pii=pair<int,int>;
mt19937_64 rng(random_device{}());
constexpr int N=407,P=998244353;
struct mint{
int d;
mint()=default;
mint(int x):d(x){}
friend std::istream&operator>>(std::istream&x,mint&y){return x>>y.d;}
friend std::ostream&operator<<(std::ostream&x,mint y){return x<<y.d;}
friend mint operator+(mint x,mint y){return (x.d+=y.d)<P?x.d:x.d-P;}
mint&operator+=(mint z){return (d+=z.d)<P?d:d-=P,*this;}
friend mint operator-(mint x,mint y){return (x.d-=y.d)<0?x.d+P:x.d;}
mint&operator-=(mint z){return (d-=z.d)<0?d+=P:d,*this;}
friend mint operator*(mint x,mint y){return int(1ll*x.d*y.d%P);}
mint&operator*=(mint z){return d=int(1ll*d*z.d%P),*this;}
static mint qpow(int x,int y=P-2){int z=1;for(;y;y>>=1,x=int(1ll*x*x%P))if(y&1)z=int(1ll*x*z%P);return z;}
friend mint operator/(mint x,mint y){return x*=qpow(y.d);}
mint&operator/=(mint z){return (*this)*=qpow(z.d);}
friend mint operator^(mint x,mint y){return qpow(x.d,y.d);}
mint&operator^=(mint z){return *this=qpow(d,z.d);}
mint operator()(mint z)const{return qpow(d,z.d);}
mint&operator[](mint z){return *this=qpow(d,z.d);}
mint inv()const{return qpow(d);}
mint pow(mint z)const{return qpow(d,z.d);}
int operator+()const{return d;}
mint operator-()const{return d?P-d:0;}
int operator~()const{return ~d;}
};
mint operator""_m(lolu x){return mint(int(x%P));}
int n,a[N][N],s[N],id[N],fa[N],b[N][N];
vector<int>g[N];
mint fac[N],ans;
void mark(int u,int t){
b[u][t]=b[t][u]=1;
for(int v:g[u])
mark(v,t);
}
bool solve(){
cin>>n;
for(int i=1;i<=n;i++){
g[i].clear();
s[i]=0;
id[i]=i;
for(int j=1;j<=n;j++){
cin>>a[i][j];
s[i]+=a[i][j];
b[i][j]=0;
}
}
if(s[1]!=n)return false;
sort(id+1,id+1+n,[](int x,int y){
if(x==1)return false;
if(y==1)return true;
if(s[x]!=s[y])
return s[x]<s[y];
for(int k=1;k<=n;k++)
if(a[x][k]!=a[y][k])
return a[x][k]<a[y][k];
return x<y;
});
for(int i=n-1;i>=1;i--){
fa[id[i]]=-1;
for(int j=i+1;j<=n;j++)
if(a[id[i]][id[j]]==1){
fa[id[i]]=id[j];
break;
}
if(fa[id[i]]==-1)return false;
}
for(int i=2;i<=n;i++)
g[fa[i]].push_back(i);
for(int i=1;i<=n;i++)
mark(i,i);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]!=b[i][j])
return false;
ans=1;
for(int i=1;i<n;){
int j=i;
while(j+1<n&&[&](){
for(int k=1;k<=n;k++)
if(a[id[j]][k]!=a[id[j+1]][k])
return false;
return true;
}())j++;
ans*=fac[j-i+1];
i=j+1;
}
return true;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);
fac[0]=fac[1]=1;
for(int i=2;i<N;i++)fac[i]=fac[i-1]*i;
int T;cin>>T;while(T--){
if(solve())cout<<ans<<'\n';
else cout<<0<<'\n';
}
return 0;
}