• [JZOJ5165] 小W的动漫


    [JZOJ5165] 小W的动漫

    (sort.cpp 1s 256M)
    小WW最近迷上了日本动漫,每天都有无数部动漫的更新等着他去看,所以他必须将所有的动漫排个顺序,当然,虽然有无数部动漫,但除了1号动漫,每部动漫都有且仅有一部动漫是它的前传(父亲),也就是说,所有的动漫形成一个树形结构。而动漫的顺序必须满足以下两个限制:
    ①一部动漫的所有后继(子孙)都必须排在它的后面。
    ②对于同一部动漫的续集(孩子),小W喜爱度高的须排在前面。
    光排序小WW还不爽,他想知道一共有多少种排序方案,并且输出它mod10007的答案。
    Input
    第一行表示T表示数据组数。
    接下来每组数据第一行n表示有多少部动漫等待排序,
    接下来n行每行第一个数tot表示这部动漫有多少部续集,
    接下来tot个数按照小WW喜爱从大到小给出它的续集的编号。
    n≤1000。
    Output
    每组数据一行数ans,表示答案mod10007的结果。
    Sample Input
    1
    5
    3 4 3 2
    0
    1 5
    0
    0
    Sample Output
    2

    Solution

    对于以X为根的子树, 其能组成的所有排序中, X及X的儿子节点的相对位置是唯一的, 而在这些点之下的点就可以变换排列.

    设f(x)表示以x为根的子树能组成的合法序列个数;

    在以fa(x)为根的子树里, x的子孙节点只能排布在x之后, 假设x后已经排列有t个节点, 那么x的子孙节点就有(C_{sz(x)-1+t}^{sz(x)-1} imes f(x))种排列方式, 这也就是对f(fa(x))造成的贡献

    最后答案就是f(1)

    Code

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int read(){
        int x=0,f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
        return x*f;
    }
    const int N=1e3+28,p=10007;
    int n,sz[N],tr[N],tot[N],son[N][N];
    int mul[N],di[N];
    int Pow(int x,int y=p-2){
        int re=1;
        while(y){
    	if(y&1)re=re*x%p;
    	y>>=1;
    	x=x*x%p;
        }
        return re;
    }
    void Pre(int n=1000){
        mul[1]=di[1]=1;
        for(int i=2;i<=n;i++){
    	mul[i]=mul[i-1]*i%p;
    	di[i]=Pow(mul[i]);
        }
    }
    int C(int n,int m){
        if(m==0||n==m)return 1;
        int re=mul[n]*di[m]%p;
        re=re*di[n-m]%p;
        return re;
    }
    void dfs(int x=1){
        tr[x]=sz[x]=1;
        int fk=0;
        for(int i=tot[x];i>=1;i--){
    	dfs(son[x][i]);
    	sz[x]+=sz[son[x][i]];
    	tr[x]=tr[x]*C(fk+sz[son[x][i]]-1,fk)%p;
    	tr[x]=tr[x]*tr[son[x][i]]%p;
    	fk+=sz[son[x][i]];
        }
    }
    signed main(){
        //freopen("sort.in","r",stdin);
        //freopen("sort.out","w",stdout);
        Pre();
        int t=read();
        while(t--){
    	memset(tr,0,sizeof(tr));
    	n=read();
    	for(int i=1;i<=n;i++){
    	    tot[i]=read();
    	    for(int j=1;j<=tot[i];j++){
    		son[i][j]=read();
    	    }
    	}
    	dfs();
    	printf("%lld
    ",tr[1]);
        }
        return 0;
    }
    /*
      1
      5
      3 4 3 2
      0
      1 5
      0
      0
    */
    
    
  • 相关阅读:
    2020年3月22日
    2021年3月21日
    2021年3月20日
    人件集阅读笔记02
    2021年3月19日
    2021年3月18日
    2021年3月17日
    2021年3月16日
    2021年3月15日
    梦断代码阅读笔记01
  • 原文地址:https://www.cnblogs.com/nlKOG/p/11488403.html
Copyright © 2020-2023  润新知