Shuffle Permutation(并查集套路)

题目大意

题目链接

给定一个N×N矩阵和一个整数k。这个矩阵的第i行第j列的项记为ai,j。这个矩阵包含1,2,…,N^2恰好一次。

西格玛可以以任意顺序任意多次重复下列两种操作。

1.你可以选择任意两行x,y,如果对于这一行里的全部数都有a[x][i]+a[y][i](1<=i<=m)小于等于k,则这两行就可以交换

1.你可以选择任意两列x,y,如果对于这一行里的全部数都有a[i][x]+a[i][y](1<=i<=n)小于等于k,则这两行就可以交换

问你通过操作能得到多少矩阵,这里面的矩阵都属不同的

题目描述

如果xxx行能和yyy行,zzz行交换,那么yyy行也可以和zzz行交换。
所以把能互相交换的部分(行,列)用并查集合并起来。每个能互相交换的连通块的总方案数就是连通块大小的阶乘。

Code

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=3e3+100;
const int mod=998244353;
typedef long long ll;
ll fac[maxn];
int pre2[maxn],sz1[maxn],sz2[maxn],pre1[maxn];
int a[maxn][maxn];
int find1(int x){
    if(pre1[x]==x){
        return pre1[x];
    }
    else{
        return pre1[x]=find1(pre1[x]);
    }
}
int find2(int x){
    if(pre2[x]==x){
        return pre2[x];
    }
    else{
        return pre2[x]=find2(pre2[x]);
    }
}
void marge1(int x,int y){
    int fx=find1(x);
    int fy=find1(y);
    if(fx!=fy){
        pre1[fx]=fy;
        sz1[fy]+=sz1[fx]; 
    } 
}
void marge2(int x,int y){
    int fx=find2(x);
    int fy=find2(y);
    if(fx!=fy){
        pre2[fx]=fy;
        sz2[fy]+=sz2[fx];
    }
}
void inint(){
    fac[0]=1;
    for(ll i =1 ;i<=55 ;i++) fac[i] = fac[i-1]*i%mod,fac[i]=fac[i]%mod;
}
int main(){
    inint();
    int n;
    ll k;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        pre1[i]=pre2[i]=i;
        sz1[i]=sz2[i]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&a[i][j]); 
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            int flag=1;
            for(int z=1;z<=n;z++){
                if(a[i][z]+a[j][z]>k){
                    flag=0;
                    break;
                }
            }
            if(flag) marge1(i,j);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            int flag=1;
            for(int z=1;z<=n;z++){
                if(a[z][i]+a[z][j]>k){
                    flag=0;
                    break; 
                }
            }
            if(flag) marge2(i,j);
        }
    }
    ll ans=1;
    for(int i=1;i<=n;i++){
        if(find1(i)==i) ans=(ans*fac[sz1[i]])%mod;
    }
    for(int i=1;i<=n;i++){
        if(find2(i)==i) ans=(ans*fac[sz2[i]])%mod;
    } 
    cout<<ans<<endl;
}

 

posted @ 2021-09-15 17:20  lipu123  阅读(63)  评论(0)    收藏  举报