zoukankan      html  css  js  c++  java
  • 【BZOJ1005/1211】[HNOI2008]明明的烦恼/[HNOI2004]树的计数 Prufer序列+高精度

    【BZOJ1005】[HNOI2008]明明的烦恼

    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

    题解:每个点在Prufer序列中出现的次数=这个点的度数-1,所以我们令m为已经确定度数的点的数量,$tot=sum D[i]-1$,那么其他位置可以随便选,方案数为$(n-2-tot)^{n-m}$。然后这些已经确定的位置可以随便排列,方案数为$C_{n-2}^{tot} imes C_{tot}^{d1} imes C_{tot-d1}^{d2} imes ...$。

    但显然结果是爆longlong的,不过可以确定答案一定是个整数。为了避免高精度除法,我们可以将分子和分母都拆成质数的几次方形式,然后分子分母做减法,最后用高精度将这些质数乘起来就行了。

    1211那题需要特判:tot!=n-2输出0;n>1且di=0输出0;di>=n输出0。

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    using namespace std;
    const int maxn=1010;
    int n,m,tot,num;
    int pri[maxn],np[maxn],lp[maxn],s[maxn],d[maxn],B[maxn];
    struct Cbig
    {
    	int a[10010],len;
    	Cbig() {memset(a,0,sizeof(a)),len=1;}
    	int & operator [] (int b) {return a[b];}
    	void operator *= (const int &b)
    	{
    		for(int i=1;i<=len;i++)	a[i]*=b;
    		for(int i=1;i<=len;i++)	a[i+1]+=a[i]/1000,a[i]%=1000;
    		while(a[len+1])	len++;
    		while(len&&!a[len])	len--;
    	}
    }ans;
    inline void add(int x,int v)
    {
    	while(x!=1)	s[lp[x]]+=v,x/=pri[lp[x]];
    }
    void init()
    {
    	int i,j;
    	for(i=2;i<=n;i++)
    	{
    		if(!np[i])	pri[++num]=i,lp[i]=num;
    		for(j=1;j<=num&&i*pri[j]<=n;j++)
    		{
    			np[i*pri[j]]=1,lp[i*pri[j]]=j;
    			if(i%pri[j]==0)	break;
    		}
    	}
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd(),tot=0,init();
    	int i;
    	for(i=1;i<=n;i++)
    	{
    		d[i]=rd();
    		if(d[i]==0)
    		{
    			printf("0");
    			return 0;
    		}
    		if(d[i]>0)	d[i]--,m++,tot+=d[i];
    	}
    	if(tot>n-2)
    	{
    		printf("0");
    		return 0;
    	}
    	ans.a[1]=ans.len=1;
    	for(i=1;i<=n-2-tot;i++)	ans*=(n-m);
    	B[n-2]++,B[n-2-tot]--;
    	for(i=1;i<=n;i++)	if(d[i]>=0)	B[d[i]]--,tot-=d[i];
    	for(i=n-2;i>=1;i--)	B[i]+=B[i+1],add(i,B[i]);
    	for(i=1;i<=n-2;i++)	while(s[i]--)	ans*=pri[i];
    	printf("%d",ans.a[ans.len]);
    	for(i=ans.len-1;i>=1;i--)	printf("%03d",ans.a[i]);
    	return 0;
    }//5 1 1 -1 -1 -1
    #include <cstdio>
    #include <iostream>
    #include <cstring>
    using namespace std;
    const int maxn=1010;
    int n,tot,num;
    int pri[maxn],np[maxn],lp[maxn],s[maxn],d[maxn],B[maxn];
    struct Cbig
    {
    	int a[10010],len;
    	Cbig() {memset(a,0,sizeof(a)),len=1;}
    	int & operator [] (int b) {return a[b];}
    	void operator *= (const int &b)
    	{
    		for(int i=1;i<=len;i++)	a[i]*=b;
    		for(int i=1;i<=len;i++)	a[i+1]+=a[i]/1000,a[i]%=1000;
    		while(a[len+1])	len++;
    		while(len&&!a[len])	len--;
    	}
    }ans;
    inline void add(int x,int v)
    {
    	while(x!=1)	s[lp[x]]+=v,x/=pri[lp[x]];
    }
    void init()
    {
    	int i,j;
    	for(i=2;i<=n;i++)
    	{
    		if(!np[i])	pri[++num]=i,lp[i]=num;
    		for(j=1;j<=num&&i*pri[j]<=n;j++)
    		{
    			np[i*pri[j]]=1,lp[i*pri[j]]=j;
    			if(i%pri[j]==0)	break;
    		}
    	}
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd(),tot=0,init();
    	int i;
    	for(i=1;i<=n;i++)
    	{
    		d[i]=rd();
    		if((n!=1&&d[i]==0)||d[i]>=n)
    		{
    			printf("0");
    			return 0;
    		}
    		d[i]--,tot+=d[i];
    	}
    	if(tot!=n-2)
    	{
    		printf("0");
    		return 0;
    	}
    	ans.a[1]=ans.len=1;
    	B[n-2]++,B[n-2-tot]--;
    	for(i=1;i<=n;i++)	if(d[i]>=0)	B[d[i]]--,tot-=d[i];
    	for(i=n-2;i>=1;i--)	B[i]+=B[i+1],add(i,B[i]);
    	for(i=1;i<=n-2;i++)	while(s[i]--)	ans*=pri[i];
    	printf("%d",ans.a[ans.len]);
    	for(i=ans.len-1;i>=1;i--)	printf("%03d",ans.a[i]);
    	return 0;
    }//5 1 1 -1 -1 -1
  • 相关阅读:
    leetcode701. Insert into a Binary Search Tree
    leetcode 958. Check Completeness of a Binary Tree 判断是否是完全二叉树 、222. Count Complete Tree Nodes
    leetcode 110. Balanced Binary Tree
    leetcode 104. Maximum Depth of Binary Tree 111. Minimum Depth of Binary Tree
    二叉树
    leetcode 124. Binary Tree Maximum Path Sum 、543. Diameter of Binary Tree(直径)
    5. Longest Palindromic Substring
    128. Longest Consecutive Sequence
    Mac OS下Android Studio的Java not found问题,androidfound
    安卓 AsyncHttpClient
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7787599.html
Copyright © 2011-2022 走看看