C/C++教程

Permutation Counting (建图(深林图,有向图变树的特性条件)+树节点贡献问题(树型dp)+(组合数)) (MINIEYE杯十六届)

本文主要是介绍Permutation Counting (建图(深林图,有向图变树的特性条件)+树节点贡献问题(树型dp)+(组合数)) (MINIEYE杯十六届),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

题目:H-Permutation Counting_MINIEYE杯第十六届华中科技大学程序设计邀请赛 (nowcoder.com)

思路:

  • 首先啊,先把题目读清楚, 给一对,(X,Y), 要满足Py>Px, 然后p(permutation )是一个1到n,且各个元素不同的数列
  • 问这个P啊有多少种排列方式
  • 首先 Py>Px , 代表着 位置 y是一定要大于 位置 x的, 利用这个可以建一个有向图,连接一个y到x的有向边
  • 什么时候符合条件? 就是没有环的时候符合条件
  • 其次 说有对(x,y) x都是不相同的, 相当于,每一个点最多只有1个父亲,于是这个性质就把图变成了树图(有向图,没有环,且父亲最多只有1个)
  • 注意这个树图是森林,没有要求是1个树.
  • 那么就转化为了,数的节点贡献问题, 该题关键就是就是他的size大小, 会拿size个数给他排大小去,对于他一定是比儿子大,他们之间的顺序就是固定的
  • 但是儿子之间的顺序没有固定,就变成了选球放盒子问题(每一个球不同),的一共种类数, 树与树之间也是如此 利用组合数解决
  • 具体看代码
#include <bits/stdc++.h>
using namespace std;
#define ri register int 
#define M  2000006

vector <int> p[M];
vector <int> q;

int n,m;

int vis[M];
int sz[M];
void dfs1(int a)
{
    vis[a]=1;
    sz[a]++;
    for(ri i=0;i<p[a].size();i++)
    {
        int b=p[a][i];
    
        dfs1(b);
        sz[a]+=sz[b];
    }
    return ;
}
long long ans=1;
const int mod=998244353;
int in[M];
long long arr[M],inv[M];
long long ksn(long long a,int n)
{
    long long ans=1;
    while(n)
    {
        if(n&1) ans=ans*a%mod;
        n>>=1;a=a*a%mod;
    }
    return ans;
}
void init(){
    
    arr[0]=1;inv[0]=1;
    for(ri i=1;i<=n;i++)
    {
        arr[i]=arr[i-1]*i%mod;
        inv[i]=ksn(arr[i],mod-2);
    }
}
long long zh(int a,int b)
{
    if(a<b) return 0;
    if(a==b||b==0) return 1;
    return arr[a]*inv[a-b]%mod*inv[b]%mod;
}
void dfs2(int a)
{
    int tmp=sz[a]-1;
    for(ri i=0;i<p[a].size();i++)
    {
        int b=p[a][i];
        ans=(ans*zh(tmp,sz[b]))%mod;
        tmp-=sz[b];
        dfs2(b);
    }
}
int main(){
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin>>n>>m;
    init();
    for(ri i=1;i<=m;i++)
    {
        int a,b;
        cin>>a>>b;
        p[b].push_back(a);
        in[a]++;
    }
    for(ri i=1;i<=n;i++)
    {
        if(in[i]==0)
        {
            q.push_back(i);
        }
    }
    for(ri i=0;i<q.size();i++)
    {
        int b=q[i];
        dfs1(b);
    }
    for(ri i=1;i<=n;i++)
    {
        if(vis[i]==0)
        {
            printf("0\n");
            return 0;
        }
    }
    int tmp=n;
    for(ri i=0;i<q.size();i++)
    {
        int a=q[i];
        ans=(ans*zh(tmp,sz[a]))%mod;
        dfs2(a);
        tmp-=sz[a];
    }
    cout<<ans;
    return 0;
    
    
    
} 
View Code

 

这篇关于Permutation Counting (建图(深林图,有向图变树的特性条件)+树节点贡献问题(树型dp)+(组合数)) (MINIEYE杯十六届)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!