C/C++教程

H. Permutation Counting 判环,计数,拓扑

本文主要是介绍H. Permutation Counting 判环,计数,拓扑,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

H. Permutation Counting

2022/7/28

传送门:https://codeforces.com/group/5zHJ4CTyoU/contest/392060/problem/H

图上计数,判环,拓扑。

题意:求n个数排列的方案数,满足m个限制条件:\(P_{x_i}<P_{y_i}\),题目保证没有相同的y

建成有向图图,是一个树林。

对于有环的图,答案为0。

对每颗树,树根用了他们的最大值,直接扔了不影响方案数,然后它的亲儿子们变成了新的树根,瓜分父亲遗产。假如树本有n个后代子节点,s个亲儿子,每个亲儿子分别有\(m_1,m_2...m_s\)个后代子节点。那么方案数有\(C_n^{m_1}*C_{n-m_1}^{m_2}...C_{m_s}^{m_s}\)

#include <bits/stdc++.h>
#define int long long
const int N = 4e6+10;
const int mo=998244353;
int a[N];
int fa[N];
int vis[N];
std::vector<int>to[N];
int ans=1;
int D[N],jc[N];
int q_pow(int a,int b){
    int res=1;
    while(b){
        if(b&1)res=res*a%mo;
        a=a*a%mo;
        b>>=1;
    }
    return res;
}
int inv(int a){
    return q_pow(a,mo-2);
}
int C(int n,int m){
    int ans=jc[n];
    ans=ans*inv(jc[m])%mo;
    ans=ans*inv(jc[n-m])%mo;
    return ans;
}
void init(){
    D[2]=1;
    for(int i=3;i<N;i++)D[i]=(i-1)*(D[i-1]+D[i-2])%mo;
    D[0]=1;
    jc[0]=1;
    for(int i=1;i<N;i++)jc[i]=jc[i-1]*i%mo;

}
bool check=1;
int dfs(int now){
    vis[now]=1;
    if(to[now].size()==0)return 1;
    int sum=0;
    
    std::vector<int>ve;
    for(int i:to[now]){
        int k=dfs(i);
        ve.push_back(k);
        sum+=k;
    }
    int re=sum;
    for(int i:ve){
        ans*=C(sum,i);
        ans%=mo;
        sum-=i;
    }
    return re+1;
}
signed main(){
    std::ios::sync_with_stdio(false);
    init();
    int n,m;std::cin>>n>>m;
    for(int i=0;i<m;i++){
        int x,y;
        std::cin>>x>>y;
        to[y].push_back(x);
        fa[x]=y;
    }
    for(int i=1;i<=n;i++)if(!fa[i])to[0].push_back(i);
    dfs(0);
    for(int i=1;i<=n;i++)if(!vis[i])ans=0;
    std::cout<<ans<<"\n";
}

这篇关于H. Permutation Counting 判环,计数,拓扑的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!