【JZOJ B組】小W的動漫
阿新 • • 發佈:2018-12-13
Description
小W最近迷上了日本動漫,每天都有無數部動漫的更新等著他去看,所以他必須將所有的動漫排個順序,當然,雖然有無數部動漫,但除了1號動漫,每部動漫都有且僅有一部動漫是它的前傳(父親),也就是說,所有的動漫形成一個樹形結構。而動漫的順序必須滿足以下兩個限制: 1、一部動漫的所有後繼(子孫)都必須排在它的後面; 2、對於同一部動漫的續集(孩子),小W喜愛度高的須排在前面。 光排序小W還不爽,他想知道一共有多少種排序方案,並且輸出它mod 10007的答案。
Input
第一行表示T表示資料組數。接下來每組資料第一行n表示有多少部動漫等待排序,接下來n行每行第一個數tot表示這部動漫有多少部續集,接下來tot個數按照小W喜愛從大到小給出它的續集的編號。
Output
每組資料一行數ans,表示答案mod 10007的結果。
Sample Input
1 5 3 4 3 2 0 1 5 0 0
Sample Output
2
Data Constraint
30%的資料: n<=10 60%的資料: n<=100 100%的資料: n<=1000
思路
其實,可以發現,如果我們每一棵子樹是固定的 只要不改變字數內的相對位置,答案就是正確的。 所以我們考慮用插板法
程式碼
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=3077,mod=10007; int t,C[maxn][maxn],f[maxn],sum[maxn],list[maxn],cnt; struct E { int to,next; }e[maxn]; void add(int u,int v) { e[++cnt].to=v; e[cnt].next=list[u]; list[u]=cnt; } void pre() { C[0][0]=1; for(int i=1; i<maxn; i++) { C[i][0]=1; for(int j=1; j<=i; j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; } } int c(int x,int y) { return C[x][y]; } void dfs(int u) { sum[u]=1; f[u]=1; for(int i=list[u]; i; i=e[i].next) { int v=e[i].to; dfs(v); f[u]=f[u]*f[v]%mod*c(sum[u]+sum[v]-2,sum[v]-1)%mod; sum[u]+=sum[v]; } } int main() { pre(); scanf("%d",&t); while(t--) { int x,n,m; scanf("%d",&n); cnt=0; memset(e,0,sizeof(e)); memset(list,0,sizeof(list)); for(int i=1; i<=n; i++) { scanf("%d",&m); for(int j=1; j<=m; j++) scanf("%d",&x),add(i,x); } dfs(1); printf("%d\n",f[1]); } }