您的位置:首页 > 其它

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序列+组合数学+高精度

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: