CF--新年场--D

关键

这种有因果关系的,确实是用图论,但是我是想用topo
最后连边失败

这里是分成多个连通块,每个连通块的点数必须和边数相同
而且如果已经算过贡献,就不在重复计算了

代码

//每一个环的点数和边数都必须要相同
//如果这个环已经乘过贡献了,那就不在次计算贡献,直接标记为1就可以了
//用并查集来统计连通块的点和边
//两个点一条边就可以了
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int M=1e5+5;
const int mod=998244353;

int a[M],b[M];;
int siz[M],cnt[M];
bool st[M];
int fa[M];
int find(int x) {
    return x==fa[x]?fa[x]:fa[x]=find(fa[x]);
}

signed main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int TT;cin>>TT;
    while(TT--) {
        int n;cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<=n;i++)cin>>b[i];
        for(int i=1;i<=n;i++)cnt[i]=st[i]=0,fa[i]=i,siz[i]=1;
        int ans=1;
        for(int i=1;i<=n;i++) {
            if(a[i]==b[i])st[a[i]]=1,ans=ans*n%mod;//自环的环,标记已成乘过了
            cnt[a[i]]++;
            fa[find(a[i])]=find(b[i]);
        }
        for(int i=1;i<=n;i++)
            if(find(i)!=i)cnt[find(i)]+=cnt[i],st[find(i)]|=st[i],siz[find(i)]++;
        //吧孩子的状态进行统计
        for(int i=1;i<=n;i++)
            if(find(i)==i) {
                if(cnt[i]!=siz[i])ans=0;//点数和边数不相同
                if(st[i]==0)ans=ans*2%mod;
            }
        cout<<ans<<endl;
    }
    return 0;
}
//当时是想着有些点是已经连了,然后把已经连过的相关的点又进行连接,模拟起来确实有些复杂
//正确性也不得而知,虽然感觉思路没啥问题
//但是还是需要简化模拟吧
posted @ 2023-01-01 11:45  basicecho  阅读(34)  评论(0)    收藏  举报