luogu P2290 [HNOI2004]樹的計數
阿新 • • 發佈:2021-06-17
題面傳送門
首先這種生成樹計數想到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); }