【JZOJ B组】小W的动漫

版权声明:转载者乖乖♂站好 https://blog.csdn.net/Eric1561759334/article/details/82951101

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]);
	}
}

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/82951101
今日推荐