标签:树形结构 结构 while play 预处理 复杂度 const 表示 lan
题目链接:http://noip.ybtoj.com.cn/problem/20053
将被敬仰的人向敬仰他的人连一条有向边,那么如果存在环显然无解。
否则由于每个点入度最多为 \(1\),所以形成了一棵树形结构。
设 \(f[x]\) 表示 \(x\) 子树内排序的方案数。考虑加入一棵子树时,\(x\) 依然排在最右,剩余位置填给任意的人,方案数为
时间复杂度 \(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;
}
标签:树形结构 结构 while play 预处理 复杂度 const 表示 lan
原文地址:https://www.cnblogs.com/stoorz/p/13679104.html