zoukankan      html  css  js  c++  java
  • [BZOJ1211]:[HNOI2004]树的计数(prufer序列)

    题目传送门


    题目描述

    一个有n个结点的树,设它的结点分别为$v_1,v_2,…,v_n$,已知第i个结点$v_i$的度数为$d_i$,问满足这样的条件的不同的树有多少棵。给定n,$d_1,d_2,…,d_n$,编程需要输出满足$d_{v_i} = d_i$的树的个数。


    输入格式

    第一行是一个正整数n,表示树有n个结点。第二行有n个数,第i个数表示$d_i$,即树的第i个结点的度数。


    输出格式

    输出满足条件的树有多少棵。


    样例

    样例输入

    4
    2 1 2 1

    样例输出

    2


    数据范围与提示

    $1 leqslant n leqslant 150$。

    输入数据保证满足条件的树不超过${10}^{17}$个。


    题解

    显然是一道prufer序列的板子题,确定n个点度数分别是为$d_1,d_2,...$时无根树个数:$frac{(n-2)!}{(d_1-1)! imes (d_2-1)! imes ...}$

    但是需要注意两个特判:

      1.要满足是一棵树则$sum limits_{i=1}^{n}d_i=2 imes n-2$。

      2.当$n=1$时显然不方便处理,则直接输出1即可。

    直接输出“0”你会惊喜的发现,你有15分!

    至于实现过程,可以使用高精暴力求,当然也可以使用分解质因数,显然后者更好实现。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int d[151];
    int pre[400],pri[400];
    long long wzc[400];
    long long ans=1LL;
    void pre_work()//预处理质因数
    {
    	for(int i=2;i<=2*n;i++)
    	{
    		if(!pri[i])
    		{
    			pri[i]=i;
    			pre[++pre[0]]=i;
    		}
    		for(int j=1;j<=pre[0];j++)
    		{
    			if(pre[j]>pri[i]||i*pre[j]>n)break;
    			pri[i*pre[j]]=pre[j];
    		}
    	}
    }
    long long qsm(long long x,long long y)
    {
    	long long rec=1;
    	while(y)
    	{
    		if(y&1)rec*=x;
    		x*=x;
    		y>>=1;
    	}
    	return rec;
    }
    int main()
    {
    	scanf("%d",&n);
    	pre_work();
    	int sum=0;
    	bool flag=0;
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&d[i]);
    		if(!d[i])flag=1;
    		sum+=d[i];
    	}
    	if(n==1&&!d[1]){puts("1");return 0;}
    	if(sum!=2*n-2||flag){puts("0");return 0;}//两个特判
    	for(int i=1;i<=n-2;i++)
    	{
    		int flag=i;
    		while(flag>1)
    		{
    			wzc[pri[flag]]++;
    			flag/=pri[flag];
    		}
    	}
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<d[i];j++)
    		{
    			int flag=j;
    			while(flag>1)
    			{
    				wzc[pri[flag]]--;
    				flag/=pri[flag];
    			}
    		}
    	}
    	for(int i=1;i<=n;i++)
    		if(wzc[i])ans=ans*qsm(i,wzc[i]);//计算答案
    	printf("%lld",ans);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    Git 基础
    SharePoint 2013 对象模型操作"网站设置"菜单
    SharePoint 2013 隐藏部分Ribbon菜单
    SharePoint 2013 Designer系列之数据视图筛选
    SharePoint 2013 Designer系列之数据视图
    SharePoint 2013 Designer系列之自定义列表表单
    SharePoint 2013 设置自定义布局页
    SharePoint 2013 "通知我"功能简介
    SharePoint 2013 创建web应用程序报错"This page can’t be displayed"
    SharePoint 禁用本地回环的两个方法
  • 原文地址:https://www.cnblogs.com/wzc521/p/11222183.html
Copyright © 2011-2022 走看看