链接
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4182
题解
从树形
d
p
dp
dp的角度去考虑这道题
先求出每棵子树的大小
s
i
z
e
i
size_i
sizei,并求出将
1...
s
i
z
e
i
1...size_i
1...sizei按照题目所讲的规则给这棵子树编号的方案数为
f
i
f_i
fi
那么
f
i
=
(
s
i
z
e
i
−
1
)
!
∏
j
∈
s
o
n
i
s
i
z
e
j
∏
j
∈
s
o
n
i
f
j
f_i={(size_i-1)!\over\prod_{j\in son_i}size_j}\prod_{j\in son_i}f_j
fi=∏j∈sonisizej(sizei−1)!j∈soni∏fj
化简一下,发现最终
a
n
s
=
f
1
=
(
n
−
1
)
!
∏
i
=
2
n
s
i
z
e
i
ans=f_1={(n-1)!\over \prod_{i=2}^nsize_i}
ans=f1=∏i=2nsizei(n−1)!
由于
m
m
m不是素数,所以分母的积没法直接求逆元
先将
m
m
m拆分,
m
=
p
1
q
1
p
2
q
2
.
.
.
p
k
q
k
m=p_1^{q_1}p_2^{q_2}...p_k^{q_k}
m=p1q1p2q2...pkqk
对于每一个
p
i
p_i
pi
我先将分子分母中的
p
p
p都提取出来,剩下的直接用逆元计算,最后再单独算
p
p
p的幂
对于不同的
p
p
p,使用中国剩余定理合并即可
代码
//中国余数定理
#include <bits/stdc++.h>
#define maxn 500010
#define cl(x) memset(x,0,sizeof(x))
#define ll long long
using namespace std;
ll N, M, size[maxn], a[maxn], m[maxn], prime[maxn], mark[maxn], p[maxn], q[maxn], tot, etot, to[maxn], head[maxn], nex[maxn];
void shai()
{
ll i, j;
for(i=2;i<maxn;i++)
{
if(!mark[i])prime[++*prime]=i;
for(j=1;j<=*prime and i*prime[j]<maxn;j++)
{
mark[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
ll read(ll x=0)
{
ll c, f=1;
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-48;
return f*x;
}
void adde(ll a, ll b){to[++etot]=b;nex[etot]=head[a];head[a]=etot;}
void dfs(ll pos, ll pre)
{
ll p;
size[pos]=1;
for(p=head[pos];p;p=nex[p])
if(to[p]!=pre)dfs(to[p],pos), size[pos]+=size[to[p]];
}
ll fastpow(ll a, ll b, ll mod)
{
ll t=a, ans=1;
for(;b;b>>=1,t=t*t%mod)if(b&1)ans=ans*t%mod;
return ans;
}
void init()
{
cl(head), cl(nex), tot=etot=0;
ll i, t, f;
N=read(), M=read();
for(i=2;i<=N;i++)adde(read(),i);
dfs(1,0);
tot=0;
for(i=1,t=M;t>1 and i<=*prime and prime[i]*prime[i]<=t;i++)
if(t%prime[i]==0)
{
tot++, p[tot]=prime[i], q[tot]=0;
while(t%p[tot]==0)t/=prime[i], q[tot]++;
}
if(t>1)p[++tot]=t, q[tot]=1;
}
void exgcd(ll a, ll b, ll &x, ll &y)
{
if(!b){x=1,y=0;return;}
ll xx, yy;
exgcd(b,a%b,xx,yy);
x=yy, y=xx-a/b*yy;
}
ll inv(ll a, ll p)
{
ll x, y;
exgcd(a,p,x,y);
return (x+p)%p;
}
void work()
{
ll i, j, k, cnt, t;
for(i=1;i<=tot;i++)
{
cnt=0;
a[i]=1;
m[i]=fastpow(p[i],q[i],M+1);
for(j=1;j<N;j++)
{
for(t=j;t%p[i]==0;t/=p[i],cnt++);
a[i]=a[i]*t%m[i];
}
for(j=2;j<=N;j++)
{
for(t=size[j];t%p[i]==0;t/=p[i],cnt--);
a[i]=a[i]*inv(t,m[i])%m[i];
}
a[i]=a[i]*fastpow(p[i],cnt,m[i])%m[i];
}
}
ll crt(ll *a, ll *m, ll n)
{
ll M=1, ans=0, i;
for(i=1;i<=n;i++)M*=m[i];
for(i=1;i<=n;i++)ans=(ans+a[i]*(M/m[i])%M*inv(M/m[i],m[i]))%M;
return ans;
}
int main()
{
shai();
ll T=read();
while(T--)init(), work(), printf("%lld\n",crt(a,m,tot));
return 0;
}