ARC107——C - Shuffle Permutation

C - Shuffle Permutation

这几天遇到了很多(2道)并查集维护连通关系的题。

此题把能够相互交换的行或者列用并查集维护,不难发现一个连通块内的点个数时 c n t cnt cnt连通块内的行或者列可以两两交换,那么对答案的贡献是 c n t ! cnt! cnt!因此预处理,然后用并查集维护连通关系即可。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=60;
const int mod=998244353;
int g[N][N];
int n,m;
int p[2*N],sz[2*N];
int find(int x) {return x==p[x]?x:p[x]=find(p[x]);}
int fact[2*N];
void merge(int x,int y)
{
    int px=find(x),py=find(y);
    if(px==py) return;
    p[px]=py;
    sz[py]+=sz[px];
}
int main()
{
    //IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++) cin>>g[i][j];
        fact[0]=1;
        for(int i=1;i<=2*n;i++) p[i]=i,sz[i]=1,fact[i]=1ll*fact[i-1]*i%mod;
        
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                bool ok1=1,ok2=1;
                for(int k=1;k<=n;k++)
                    if(g[i][k]+g[j][k]>m) ok1=0;
                
                for(int k=1;k<=n;k++)
                    if(g[k][i]+g[k][j]>m) ok2=0;
                if(ok1) merge(i,j);
                if(ok2) merge(i+n,j+n);
            }
        ll res=1;
        for(int i=1;i<=2*n;i++)
            if(p[i]==i)
                res=res*fact[sz[i]]%mod;
        cout<<res<<'\n';
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值