码迷,mamicode.com
首页 > 其他好文 > 详细

【YbtOJ#10053】合影队形

时间:2020-09-18 03:05:10      阅读:43      评论:0      收藏:0      [点我收藏+]

标签:树形结构   结构   while   play   预处理   复杂度   const   表示   lan   

题目

题目链接:http://noip.ybtoj.com.cn/problem/20053
技术图片

思路

将被敬仰的人向敬仰他的人连一条有向边,那么如果存在环显然无解。
否则由于每个点入度最多为 \(1\),所以形成了一棵树形结构。
\(f[x]\) 表示 \(x\) 子树内排序的方案数。考虑加入一棵子树时,\(x\) 依然排在最右,剩余位置填给任意的人,方案数为

\[f‘[x]=f[x]\times f[v]\times \binom{size[x]+size[v]-1}{size[v]} \]

时间复杂度 \(O(n\log \operatorname{MOD})\)
由于出题人很不良心地要求每次模数都不一样,所以必须每次预处理阶乘和逆元。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const ll N=500010;
ll Q,n,m,MOD,tot,head[N],deg[N],cnt[N],size[N],fac[N];
ll ans,f[N];

void prework()
{
	memset(head,-1,sizeof(head));
	memset(deg,0,sizeof(deg));
	memset(cnt,0,sizeof(cnt));
	tot=0; ans=fac[0]=1;  
	for (ll i=1;i<=n;i++)
		fac[i]=fac[i-1]*i%MOD;
}

struct edge
{
	ll next,to;
}e[N];

void add(ll from,ll to)
{
	e[++tot].to=to;
	e[tot].next=head[from];
	head[from]=tot;
}

bool topsort()
{
	queue<int> q;
	for (ll i=1;i<=n;i++)
		if (!deg[i]) q.push(i);
	while (q.size())
	{
		ll u=q.front();
		q.pop();
		for (ll i=head[u];~i;i=e[i].next)
		{
			ll v=e[i].to;
			if (cnt[v]<deg[v])
			{
				cnt[v]++;
				if (cnt[v]==deg[v])
					q.push(v);
			}
		}
	}
	for (ll i=1;i<=n;i++)
		if (cnt[i]<deg[i]) return 0;
	return 1;
}

ll fpow(ll x,ll k)
{
	ll ans=1;
	for (;k;k>>=1,x=x*x%MOD)
		if (k&1) ans=ans*x%MOD;
	return ans;
}

ll C(ll n,ll m)
{
	ll inv=fpow(fac[m]*fac[n-m]%MOD,MOD-2);
	return fac[n]*inv%MOD;
}

void dfs(ll x)
{
	f[x]=1; size[x]=0;
	for (ll i=head[x];~i;i=e[i].next)
	{
		ll v=e[i].to;
		dfs(v);
		size[x]+=size[v];
		f[x]=C(size[x],size[v])*f[v]%MOD*f[x]%MOD;
	}
	size[x]++;
}

int main()
{
	freopen("photo.in","r",stdin);
	freopen("photo.out","w",stdout);
	scanf("%lld",&Q);
	while (Q--)
	{
		scanf("%lld%lld%lld",&n,&m,&MOD);
		prework();
		for (ll i=1,x,y;i<=m;i++)
		{
			scanf("%lld%lld",&x,&y);
			add(y,x);
			deg[x]++;
		}
		if (!topsort()) 
		{
			printf("0\n");
			continue;
		}
		ll s=0;
		for (ll i=1;i<=n;i++)
			if (!deg[i])
			{
				dfs(i);
				s+=size[i];
				ans=ans*f[i]*C(s,size[i])%MOD;
			}
		printf("%lld\n",ans);
	}
	return 0;
}

【YbtOJ#10053】合影队形

标签:树形结构   结构   while   play   预处理   复杂度   const   表示   lan   

原文地址:https://www.cnblogs.com/stoorz/p/13679104.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!