BZOJ1005 明明的烦恼 (prufer序列 组合数 高精度)
2017-04-07 07:44
399 查看
题目大意
自从明明学了树的结构,就对奇怪的树产生了兴趣……给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树?题解
prufer序列有两个性质:表示大小为n的树的prufer序列的长度为n-2;
树上的每个结点在prufer序列上出现的次数为“度数-1”。
所以说限定了某些点的度数之后,问题就转化为了排列组合问题,在这里设m为未限定度数的结点的个数,left为序列中空余位置的个数。
所以(这里直接搬PoPoQQQ大爷的公式)
ans=(n-2)!/(dge1-1)!/(dge2-1)!/…/(dgek-1)!/left! * m^left
代码:
(一开始公式少打了一半还查了好长时间的高精…)#include <cstdio> #include <iostream> using namespace std; const int maxn=int(1e3)+11; int n; int d[maxn]; bool prime[maxn]; int pri[maxn],top; void init() { prime[1]=true; for(register int i=2;i<maxn;++i) if(!prime[i]) { pri[++top]=i; for(register int j=i<<1;j<maxn;j+=i) prime[j]=true; } } struct INT10 { int v[50000],len; INT10() {} INT10(int x) { for(len=0;x;x/=10) v[++len]=x%10; return; } inline INT10 operator * (const INT10 &b) const { register INT10 res; res.len=0; register int i,j; for(i=0;i<=len+b.len;++i) res.v[i]=0; for(i=1;i<=b.len;++i) { for(j=1;j<=len;++j) { int sco=b.v[i]*v[j]; res.v[i+j-1]+=sco%10; res.v[i+j]+=sco/10; } } for(i=1;i<=len+b.len;++i) if(res.v[i]>=10) { res.v[i+1]+=res.v[i]/10; res.v[i]%=10; } for(i=len+b.len;i;--i) if(res.v[i]) { res.len=i; break; } return res; } void print() { if(len==0) {printf("0\n"); return;} for(int i=len;i;--i) printf("%d",v[i]); printf("\n"); } }; struct INT { int v[200]; inline INT() { for(register int i=1;i<=170;++i) v[i]=0; } inline INT(int x) { for(register int i=1;i<=170;++i) v[i]=0; int pos=1; while(x>1) { if(x%pri[pos]!=0) {++pos; continue;} while(x%pri[pos]==0) {x/=pri[pos], ++v[pos];} } } long long val() { long long res=1; for(int i=1;i<=170;i++) if(v[i]) for(int j=1;j<=v[i];j++) res*=pri[i]; return res; } inline INT operator * (const INT &b) const { INT R; for(register int i=1;i<=170;++i) R.v[i]=v[i]+b.v[i]; return R; } inline INT operator / (const INT &b) const { INT R; for(register int i=1;i<=170;++i) R.v[i]=v[i]-b.v[i]; return R; } }fact[maxn]; INT fstpow(INT a,int k) { for(int i=1;i<=170;i++) a.v[i]*=k; return a; } int main() { #ifndef ONLINE_JUDGE freopen("tree2.in.txt","r",stdin); freopen("output.txt","w",stdout); #endif // ONLINE_JUDGE scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&d[i]); init(); for(int i=2;i<=n;i++) fact[i]=fact[i-1]*INT(i); int left=n-2, m=n; INT ans=fact[n-2]; for(int i=1;i<=n;i++) if(d[i]!=-1) ans=ans/fact[d[i]-1], m--, left-=d[i]-1; ans=ans/fact[left]; ans=ans*fstpow(INT(m),left); INT10 ans10(1); for(int i=1;i<=170;i++) if(ans.v[i]) for(int j=1;j<=ans.v[i];j++) ans10=ans10*INT10(pri[i]); ans10.print(); return 0; } /** ans=(n-2)!/(d1-1)!/(d2-1)!/.../(dk-1)!/left! * m^left **/
相关文章推荐
- BZOJ 1005-明明的烦恼-(prufer序列+高精度)
- Prufer编码 & [bzoj 1005] [HNOI2008]明明的烦恼:Prufer编码,组合数学,高精度
- 【BZOJ1005/1211】[HNOI2008]明明的烦恼/[HNOI2004]树的计数 Prufer序列+高精度
- 【bzoj1005】[HNOI2008]明明的烦恼 Prufer序列+高精度
- BZOJ 1005 [HNOI2008]明明的烦恼 (Prufer编码 + 组合数学 + 高精度)
- BZOJ 1005 [HNOI2008]明明的烦恼 purfer序列,排列组合
- 【BZOJ1005】明明的烦恼(HNOI2008)-Prufer序列+组合计数+高精度
- bzoj1005: [HNOI2008]明明的烦恼 [prufer序列]
- BZOJ_1005_ [HNOI2008]_明明的烦恼_(组合数学+purfer_sequence+高精度+分解因数+快速幂)
- [bzoj1005]:[HNOI2008]明明的烦恼(prufer序列+质因数分解+高精乘)
- 1005: [HNOI2008]明明的烦恼 (prufer编码,排列组合,质因数分解,高精度)
- [prufer序列]BZOJ1005: [HNOI2008]明明的烦恼
- BZOJ 1005: [HNOI2008]明明的烦恼(prufer序列->无根树表达)
- CODEVS 1850 (BZOJ 1005) 明明的烦恼 Prüfer 序列
- BZOJ 1005: [HNOI2008]明明的烦恼( 组合数学 + 高精度 )
- bzoj 1005 明明的烦恼 【Prufer序列】
- [BZOJ1005][HNOI2008]明明的烦恼(prufer序列+组合数学+高精度)
- 【组合数学】【高精度】【prufer数列】【HNOI 2008】【bzoj 1005】明明的烦恼
- [BZOJ1005]HNOI2008 明明的烦恼|prufer编码|排列组合
- 【BZOJ 1005】[HNOI2008]明明的烦恼 【Prufer序列】