【LOJ6044】「雅礼集训 2017 Day8」共(prufer序列)

点此看题面

  • 求有多少棵(n)个点的、以(1)号点为根的有根树,满足恰好有(k)个点深度为奇数((1)号点深度为(1))。
  • (nle5 imes10^5),当(n>10^3)时模数为(998244353)

(prufer)序列的经典应用

首先有一个组合数(C_{n-1}^{k-1}),表示从除(1)之外的点中选出剩余的深度为奇数的点的方案数。

由于只可能奇数度数和偶数度数的点之间存在边,且每对奇数度数和偶数度数的点之间都可能存在边,因此我们现在有一张两边点数分别是(k)(n-k)的完全二分图。

然后就可以借鉴【BZOJ4766】文艺计算姬的结论,这样一张图中的生成树个数就是(k^{n-k-1}cdot(n-k)^{k-1})

代码:(O(n^2)/O(n))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define BN 1000
using namespace std;
int n,k,X;I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
I int Fac(RI x) {RI t=1;W(x) t=1LL*t*(x--)%X;return t;}//暴力算阶乘
int c[BN+5][BN+5];I int C(CI x,CI y)//组合数
{
	if(x<=BN) {for(RI i=c[0][0]=1;i<=x;++i) for(RI j=c[i][0]=1;j<=i;++j) c[i][j]=(c[i-1][j-1]+c[i-1][j])%X;return c[x][y];}//暴力求组合数
	else return 1LL*Fac(x)*QP(1LL*Fac(y)*Fac(x-y)%X,X-2)%X;//x>BN时必定有逆元,套用组合数计算公式
}
int main()
{
	return scanf("%d%d%d",&n,&k,&X),printf("%d
",1LL*C(n-1,k-1)*QP(k,n-k-1)%X*QP(n-k,k-1)%X),0;//选点方案×建树方案
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/LOJ6044.html