zoukankan      html  css  js  c++  java
  • 【组合计数】树上拓扑序 UVA11174 Stand in a Line

    板子题:
    https://www.luogu.com.cn/problem/UVA11174

    分析

    整个图形成了一片森林,我们记一棵树(根节点记为 (root))的排序方案数为 (f[root])

    我们记 (root) 以下的子节点(即它们的父节点为 (root))为 (c_1,c_2...c_k)

    方便起见,记 (sz[u]) 为以其为根的子树大小。

    我们看看如何选取可以构成一个合法的序列:

    首先序列第一个元素必然是根 (root)

    对子树内部的点进行排序,由乘法原理知一定有 (prod_{i=1}^k f[c_i]) 种方案。

    假设每棵子树内部的点已经排好一定的顺序,那么每个子树内的点都可以看成是相同的元素,因此排列计数的方案数为 (frac{(sz[root]-1)!}{prod_{i=1}^k sz[c_i]!})

    因此由乘法原理,总共的方案数为:

    [f[root] = prod_{i=1}^k f[c_i] imes frac{(sz[root]-1)!}{prod_{i=1}^k sz[c_i]!} ]

    假设 (c_i)(k_i') 个子节点(记为 (c'_j)),类似地有:

    [f[c_i] = prod_{j=1}^{k_i'} f[c'_j] imes frac{(sz[c_i]-1)!}{prod_{i=1}^{k_i'} sz[c'_j]!} ]

    对所有节点求积,即得

    [f[root] =frac{(sz[root]-1)!}{prod sz[u]} ]

    其中 (u) 代表除了根以外的所有节点。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    using ll=long long;
    
    const int N=4e4+5, M=N<<1, mod=1e9+7;
    
    int n, m;
    
    struct node{
    	int to, next;
    }e[M];
    
    int h[N], tot;
    
    void add(int u, int v){
    	e[tot].to=v, e[tot].next=h[u], h[u]=tot++;
    }
    
    bool vis[N];
    int sz[N];
    
    void dfs(int u, int fa){
    	sz[u]=1;
    	for(int i=h[u]; ~i; i=e[i].next){
    		int go=e[i].to;
    		if(go==fa) continue;
    		
    		dfs(go, u);
    		sz[u]+=sz[go];
    	}	
    }
    
    ll fpow(ll x,ll p)
    {
        ll res=1;
        for(;p;p>>=1,x=x*x%mod)
            if(p&1)res=res*x%mod;
        return res%mod;
    }
    
    ll inv(ll x){
    	return fpow(x,mod-2)%mod;
    }
    
    ll fac[N];
    
    void init(){
    	fac[0]=1;
    	for(int i=1; i<N; i++) fac[i]=fac[i-1]*i%mod;
    }
    
    ll C(ll a, ll b){
    	return fac[a]*inv(fac[b])%mod*inv(fac[a-b])%mod;
    }
    
    signed main(){
    	init();
    	
    	int T; cin>>T;
    	while(T--){
    		memset(h, -1, sizeof h), tot=0;
    		memset(vis, 0, sizeof vis);
    		cin>>n>>m;
    		
    		for(int i=0; i<m; i++){
    			int u, fa; cin>>u>>fa;
    			add(fa, u), add(u, fa);
    			vis[u]=true;
    		}
    		
    		for(int i=1; i<=n; i++) if(!vis[i]) add(i, 0), add(0, i);
    		
    		dfs(0, -1);
    		
    		int t=1;
    		
    		for(int i=1; i<=n; i++) t=t*inv(sz[i])%mod; 
    		
    		cout<<fac[sz[0]-1]*t%mod<<endl;
    	}	
    	return 0;
    }
    
  • 相关阅读:
    (新)Linux 安装、配置 MondoDB
    Docker 简介
    Windows 环境下的mysql安装及端口更换详解
    Jenkins的使用
    .Net Core Web API 上传图片或文件
    (不适用.Net Core)layui+WebApi上传文件、上传图片
    (不适用于.Net Core环境)jquery+WebAPI 上传文件、图片
    Linux .Net Core发布项目及搭建
    Jquery+JavaScript 随笔
    Vue 随笔
  • 原文地址:https://www.cnblogs.com/Tenshi/p/15080743.html
Copyright © 2011-2022 走看看