BZOJ 1005 [HNOI2008]明明的烦恼
2016-07-20 18:14
555 查看
给定一棵n个节点的树的节点的度数,其中一些度数无限制,求可以生成多少种树。
用到了Prufer数列的知识。
度娘:
Prufer数列:是由有一个对于顶点标过号的树(标号树)转化来的数列,点数为n的树转化来的Prufer数列长度为n-2。由Heinz Prufer于1918年在证明Cayley定理时首次提出。
Cayley定理:一个完全图K_n有n^(n-2)棵生成树,换句话说n个节点的带标号的无根树有n^(n-2)个。
可以证明带标号无根树和Prüfer编码之间形成一一对应的关系。(具体见matrix67)
推论:
(1)标号完全二分图(一部分的顶点标号1到n1,另一部分的顶点标号n1+1到n)的生成树总数等于nn2−11nn1−12,其中n2=n−n1。
(2)n个节点的度依次为D1, D2, …, Dn的标号无根树共有(n-2)! / [ (D1-1)!(D2-1)!..(Dn-1)! ]个,因为此时Prüfer编码中的数字i恰好出现Di-1次。
matrix67:
http://www.matrix67.com/blog/archives/682
PoPoQQQ:
http://blog.csdn.net/popoqqq/article/details/40182169
acvc:
http://www.cnblogs.com/acvc/p/3629227.html
Prufer序列+组合数学+高精度
用到了Prufer数列的知识。
度娘:
Prufer数列:是由有一个对于顶点标过号的树(标号树)转化来的数列,点数为n的树转化来的Prufer数列长度为n-2。由Heinz Prufer于1918年在证明Cayley定理时首次提出。
Cayley定理:一个完全图K_n有n^(n-2)棵生成树,换句话说n个节点的带标号的无根树有n^(n-2)个。
可以证明带标号无根树和Prüfer编码之间形成一一对应的关系。(具体见matrix67)
推论:
(1)标号完全二分图(一部分的顶点标号1到n1,另一部分的顶点标号n1+1到n)的生成树总数等于nn2−11nn1−12,其中n2=n−n1。
(2)n个节点的度依次为D1, D2, …, Dn的标号无根树共有(n-2)! / [ (D1-1)!(D2-1)!..(Dn-1)! ]个,因为此时Prüfer编码中的数字i恰好出现Di-1次。
matrix67:
http://www.matrix67.com/blog/archives/682
PoPoQQQ:
http://blog.csdn.net/popoqqq/article/details/40182169
acvc:
http://www.cnblogs.com/acvc/p/3629227.html
Prufer序列+组合数学+高精度
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cassert> #include<ctime> #include<bitset> #include<queue> #include<set> #define inf (1<<30) #define INF (1ll<<62) #define prt cout<<#x<<":"<<x<<" " #define prtn cout<<#x<<":"<<x<<endl using namespace std; typedef long long ll; template<class T>void sc(T &x){ x=0;char c;int f=1; while(c=getchar(),c<48)if(c=='-')f=-1; do x=x*10+(c^48); while(c=getchar(),c>47); x*=f; } template<class T>void nt(T x){ if(!x)return; nt(x/10); putchar('0'+x%10); } template<class T>void pt(T x){ if(x<0)putchar('-'),x=-x; if(!x)putchar('0'); else nt(x); } const int maxn=1005; int n,rem=0,use=0; int prime[maxn],tot; int cnt[maxn]; bool mark[maxn]; void init(){ for(int i=2;i<=n;i++){ if(!mark[i]){ prime[++tot]=i; for(int j=i<<1;j<=n;j+=i) mark[j]=true; } } } void update(int x,int f){ for(int i=1;i<=tot&&prime[i]<=x;i++){ for(int t=x/prime[i];t;t/=prime[i]) cnt[i]+=t*f; } } struct BigInt{ int v[808]; int len; BigInt(){memset(v,0,sizeof(v));} BigInt(int x){ memset(v,0,sizeof(v)); v[0]=x;len=1; } void print(){ printf("%d",v[len-1]); for(int i=len-2;i>=0;i--) printf("%04d",v[i]); puts(""); } BigInt operator +(const BigInt &b)const{ BigInt c; c.len=max(len,b.len); for(int i=0;i<c.len;i++){ c.v[i]+=v[i]+b.v[i]; if(c.v[i]>=10000){ c.v[i]-=10000; c.v[i+1]++; } } if(c.v[c.len]>0)c.len++; return c; } BigInt operator *(const BigInt &b)const{ BigInt c; for(int i=0;i<len;i++) for(int j=0;j<b.len;j++){ c.v[i+j]+=v[i]*b.v[j]; if(c.v[i+j]>=10000){ c.v[i+j+1]+=c.v[i+j]/10000; c.v[i+j]%=10000; } } c.len=len+b.len-1; if(c.v[c.len]>0)c.len++; while(c.len>=2&c.v[c.len-1]==0)c.len--; return c; } BigInt operator^(int b){ BigInt c=*this; BigInt res(1); for(;b;b>>=1,c=c*c) if(b&1)res=res*c; return res; } }res(1); int main(){ // freopen("pro.in","r",stdin); // freopen("chk.out","w",stdout); sc(n); init(); update(n-2,1); use=n-2; for(int u,i=1;i<=n;i++){ sc(u); if(u!=-1){ update(u-1,-1); use-=u-1; } else rem++; } if(use<0){ puts("0"); return 0; } update(use,-1); for(int i=1;i<=tot;i++){ if(!cnt[i])continue; BigInt b(prime[i]); res=res*(b^cnt[i]); } BigInt c(rem); res=res*(c^use); res.print(); return 0; }
相关文章推荐
- Catalan数总结
- caffe源码学习:layer
- android补间动画(Tween Animation)
- Linux内核移植与启动
- Codelgniter框架使用UEditor问题。
- 美素数<hdoj4548>
- IntelliJ IDEA中如何设置30分钟自动刷新svn
- codeforces水题100道 第十八题 Codeforces Round #289 (Div. 2, ACM ICPC Rules) A. Maximum in Table (brute force)
- listView分割线的相关设置
- lintcode minimum-depth-of-binary-tree 二叉树最小深度
- 4-4 求自定类型元素的平均 (10分)
- 安卓端发送短信
- 分拆素数和<hdoj2098>
- MIT6.824 课程学习初步
- java开发操作系统内核:让内核突破512字节的限制
- MongoDB知识整理
- MySQL的btree索引和hash索引的区别
- jQuery在IE7和8下setInterval失效的问题
- Spark & Zeppelin
- linux 统计硬盘大小