把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P2290 [HNOI2004]树的计数

题面传送门
首先这种生成树计数想到Prufer序列。
然后因为度数为\(d_i\)的点会在Prufer序列中出现\(d_i-1\)次所以直接重排列公式即可。
然而这个没有模数什么的。
于是就要分解完质因数后再乘。
时间复杂度\(O(nlogn)\)
code:

#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 150
#define M 100000
#define eps (1e-5)
#define mod (1<<31)
#define U unsigned int
using namespace std;
int n,x,A[N+5],G[N+5],fl[N+5],pre[N+5],pr[N+5],ph,ToT; ll Ans=1;
int main(){
	freopen("1.in","r",stdin);
	re int i,j;scanf("%d",&n);if(n==1){scanf("%d",&x);printf("%d\n",x?0:1);return 0;}
	A[n-2]++;for(i=2;i<=n;i++){
		!fl[i]&&(pr[++ph]=i,pre[i]=i);for(j=1;j<=ph&&pr[j]*i<=n;j++){fl[pr[j]*i]=1;pre[pr[j]*i]=pr[j];if(i%pr[j]==0) break;}
	}
	for(i=1;i<=n;i++){scanf("%d",&x),A[x-1]--,ToT+=x;if(!x){printf("0\n");return 0;}}if(ToT!=2*n-2){printf("0\n");return 0;}
	for(i=n;i;i--) A[i]+=A[i+1];
	for(i=1;i<=n;i++){x=i;while(x^1)G[pre[x]]+=A[i],x/=pre[x];}
	for(i=1;i<=n;i++) while(G[i]--) Ans*=i;printf("%d\n",Ans);
}
posted @ 2021-06-17 20:46  275307894a  阅读(41)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end