标签:数学,高精度
Description
自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在
任意两点间连线,可产生多少棵度数满足要求的树?
Input
第一行为N(0 < N < = 1000),
接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1
Output
一个整数,表示不同的满足要求的树的个数,无解输出0
Sample Input
3
1
-1
-1
Sample Output
2
HINT
两棵树分别为1-2-3;1-3-2
分析:针对N==1和存在Di==0的情况可以先进行特判
正解关于树的prufer编码,可以参考这篇博客
这样就可以用prufer编码存储树了
对于M个无限制的节点,存储方案为M^(n-2-tot)
其余限制的节点,有C(tot,n-2)种方案
之后就转化为高精度除法的问题(今年初赛的坑高精度除法…)
其实可以将除法转化为乘法的问题,质因数分解,累程求ans,高精度过程中使用了压位技巧
Code
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define mem(x,num) memset(x,num,sizeof x)
using namespace std;
inline LL read()
{
LL f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int maxn=1006,mod=1e4;
int d[maxn],num[maxn],pri[maxn],ans[maxn],l=1,n,m,tot,x,cnt;
inline bool jud(int x){
rep(i,2,sqrt(x))if(x%i==0)return 0;
return 1;
}
inline void mul(int x){
rep(i,1,l)ans[i]*=x;
rep(i,1,l){
ans[i+1]+=ans[i]/mod;
ans[i]%=mod;
}
while(ans[l+1]>0){
l++;
ans[l+1]=ans[l]/mod;
ans[l]%=mod;
}
}//高精度压位
void solve(int a,int f){
rep(k,1,a){
int x=k;
rep(i,1,cnt){
if(x<=1)break;
while(x%pri[i]==0){num[i]+=f;x/=pri[i];}
}
}
}//num[i]打上标记,等最后一起累乘
int main()
{
rep(i,2,1000)
if(jud(i))pri[++cnt]=i;//统计质数的个数
ans[1]=1;
n=read();
if(n==1){
x=read();
if(!x)printf("1");
else printf("0");
return 0;
}//特判N==1的情况
rep(i,1,n){
d[i]=read();
if(!d[i]){printf("0");return 0;}
if(d[i]==-1)m++;
else{d[i]--;tot+=d[i];}
}
if(tot>n-2){printf("0");return 0;}
solve(n-2,1);
solve(n-2-tot,-1);
rep(i,1,n)
if(d[i])solve(d[i],-1);
rep(i,1,cnt)
while(num[i]--)mul(pri[i]);
rep(i,1,n-2-tot)mul(m);
dep(i,l,1)if(i==l)printf("%d",ans[i]);else printf("%04d",ans[i]);
return 0;
}