zoukankan      html  css  js  c++  java
  • [BZOJ1005][HNOI2008]明明的烦恼&&[BZOJ1211][HNOI2004]树的计数【prufer序列】

    【题目描述】

     自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在
    任意两点间连线,可产生多少棵度数满足要求的树?

    【题解】

        每个prufer序列对应一棵树。

        每个点在prufer序列中出现的次数=度数-1,组合数计算即可。

        记得特判 n==1 的情况。

    /* --------------
        user Vanisher
        problem bzoj-1005 && bzoj-1211
    ----------------*/
    # include <bits/stdc++.h>
    # define	N 		1010 
    # define 	MN 		5010
    using namespace std;
    int a[N],cnt,n,inc[N],num[N][N],p[N],pnum,now;
    struct number{
    	int num[MN];
    }t,x,ans;
    number operator *(number x, number y){
    	memset(t.num,0,sizeof(t.num));
    	for (int i=1; i<=x.num[0]; i++)
    		for (int j=1; j<=y.num[0]; j++)
    			t.num[i+j-1]+=x.num[i]*y.num[j];
    	t.num[0]=x.num[0]+y.num[0]-1; int i;
    	for (i=1; i<=t.num[0]||t.num[i]!=0; i++)
    		t.num[i+1]+=t.num[i]/10, t.num[i]%=10;
    	t.num[0]=i-1;
    	return t;
    }
    number mypow(int xx, int y){ 
    	memset(x.num,0,sizeof(x.num));
    	while (xx>0){
    		x.num[0]++;
    		x.num[x.num[0]]=xx%10;
    		xx/=10;
    	}
    	number i=x; 
    	x.num[0]=1; x.num[1]=1;
    	while (y>0){
    		if (y%2==1) x=x*i;
    		i=i*i;
    		y/=2;
    	}
    	return x;
    }
    void pre(int n){
    	for (int i=2; i<=n; i++){
    		int j=i;
    		for (int k=2; k*k<=j; k++)
    			while (j%k==0){
    				num[i][k]++;
    				j/=k;
    			}
    		if (j!=1) num[i][j]++;
    		if (j==i) p[++pnum]=i;
    	}
    }
    int C(int n, int m){
    	for (int i=n; i>=n-m+1; i--) inc[i]++;
    	for (int i=1; i<=m; i++) inc[i]--;
    }
    int read(){
    	int tmp=0, fh=1; char ch=getchar();
    	while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    	while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    	return tmp*fh;
    }
    int main(){
    	n=read(); 
    	pre(n); 
    	ans.num[0]=1, ans.num[1]=1;
    	for (int i=1; i<=n; i++){
    		a[i]=read();
    		if (a[i]==0&&n!=1){
    			puts("0");
    			return 0;
    		}
    		if (a[i]>0) now=now+(a[i]-1);
    	}
    	if (n==1&&a[1]==0) {
    		puts("1");
    		return 0;
    	}
    	if (now!=n-2){
    		puts("0");
    		return 0;
    	}
    	if (now>n-2)
    		printf("%d
    ",0);
    		else{
    			now=n-2, cnt=n;
    			for (int i=1; i<=n; i++){
    				if (a[i]>0){
    					cnt--;
    					C(now,a[i]-1);
    					now=now-(a[i]-1);
    				}
    			}
    			for (int i=1; i<=n; i++){
    				int tmp=inc[i]; inc[i]=0;
    				for (int j=1; j<=pnum; j++)
    					inc[p[j]]+=num[i][p[j]]*tmp;
    			}
    			for (int i=1; i<=pnum; i++)
    				ans=ans*mypow(p[i],inc[p[i]]);
    			ans=ans*mypow(cnt,now);
    			for (int i=ans.num[0]; i>=1; i--)
    				printf("%d",ans.num[i]);
    			printf("
    "); 
    		}
    	return 0;
    }
    

  • 相关阅读:
    android gallery 自定义边框+幻灯片
    C/C++学习笔记---高地址、低地址、大段字节序、小段字节序
    C#学习笔记--详解委托,事件与回调函数
    Clr Via C#读书笔记---计算限制的异步操作
    Clr Via C#读书笔记---CLR寄宿和应用程序域
    Clr Via C#读书笔记---程序集的加载和反射
    Clr Via C#读书笔记---垃圾回收机制
    Clr Via C#读书笔记---线程基础
    CLR via C#(18)——Enum
    CLR via C#(17)--接口
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136022.html
Copyright © 2011-2022 走看看