【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} \times C_{tot}^{d1} \times C_{tot-d1}^{d2} \times ...$。

但显然结果是爆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

【BZOJ1005/1211】[HNOI2008]明明的烦恼/[HNOI2004]树的计数 Prufer序列+高精度的更多相关文章

  1. BZOJ 1211 HNOI2004 树的计数 Prufer序列

    题目大意:给定一棵树中全部点的度数,求有多少种可能的树 Prufer序列.详细參考[HNOI2008]明明的烦恼 直接乘会爆long long,所以先把每一个数分解质因数.把质因数的次数相加相减.然后 ...

  2. Luogu P2290 [HNOI2004]树的计数 Prufer序列+组合数

    最近碰了$prufer$ 序列和组合数..于是老师留了一道题:P2624 [HNOI2008]明明的烦恼 qwq要用高精... 于是我们有了弱化版:P2290 [HNOI2004]树的计数(考一样的可 ...

  3. bzoj1211: [HNOI2004]树的计数 prufer序列裸题

    一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, …, dn,编程需要输出满足d(vi)=di ...

  4. BZOJ1211: [HNOI2004]树的计数(prufer序列)

    Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2987  Solved: 1111[Submit][Status][Discuss] Descript ...

  5. [HNOI2004] 树的计数 - prufer序列

    给定树每个节点的 degree,问满足条件的树的数目. \(n\leq 150, ans \leq 10^{17}\) Solution 注意特判各种坑点 \(\sum d_i - 1 = n-2\) ...

  6. 「BZOJ1005」[HNOI2008] 明明的烦恼

    「BZOJ1005」[HNOI2008] 明明的烦恼 先放几个prufer序列的结论: Prufer序列是一种对有标号无根树的编码,长度为节点数-2. 具体存在无根树转化为prufer序列和prufe ...

  7. 【BZOJ1005】[HNOI2008]明明的烦恼(prufer序列)

    [BZOJ1005][HNOI2008]明明的烦恼(prufer序列) 题面 BZOJ 洛谷 题解 戳这里 #include<iostream> #include<cstdio> ...

  8. 树的计数 + prufer序列与Cayley公式(转载)

    原文出处:https://www.cnblogs.com/dirge/p/5503289.html 树的计数 + prufer序列与Cayley公式 学习笔记(转载) 首先是 Martrix67 的博 ...

  9. 【bzoj1005】[HNOI2008]明明的烦恼

    1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4175  Solved: 1660[Submit][Stat ...

随机推荐

  1. SQLyog之MySQL客户端的下载、安装和使用(企业版)(破解)

    本博文的主要内容有 .SQLyog的下载 .SQLyog的安装 .SQLyog的使用 1.SQLyog_Enterprise的下载 比如,我这里,是放在D:\SoftWare 继续

  2. Mockito 相关资料

    https://monkeyisland.pl/2008/04/26/asking-and-telling/ http://qiuguo0205.iteye.com/blog/1456528 http ...

  3. mac 系统使用macaca inspector 获取iphone真机应用元素

    1.安装brew 软件包管理工具:/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/inst ...

  4. blender, knife工具

    点击Knife按钮开始切割,MLB在边上确认分割点,return键完成切割,MRB取消切割(这些在窗口下面的信息提示栏中都有写,如图中如示).

  5. atitit.GUI图片非规则按钮跟动态图片切换的实现模式总结java .net c# c++ web html js

    atitit.GUI图片非规则按钮跟动态图片切换的实现模式总结java .net c# c++ web html js 1. 图片按钮的效果总结 1 1.1. 按钮图片自动缩放的. 1 1.2. 不要 ...

  6. 李洪强iOS经典面试题35-按层遍历二叉树的节点

    李洪强iOS经典面试题35-按层遍历二叉树的节点 问题 给你一棵二叉树,请按层输出其的节点值,即:按从上到下,从左到右的顺序. 例如,如果给你如下一棵二叉树:    3   / \  9  20   ...

  7. 李洪强iOS经典面试题34-求两个链表表示的数的和

    李洪强iOS经典面试题34-求两个链表表示的数的和 问题 给你两个链表,分别表示两个非负的整数.每个链表的节点表示一个整数位. 为了方便计算,整数的低位在链表头,例如:123 在链表中的表示方式是: ...

  8. rip中的连续子网以及不连续子网

    RIPv1 RIPv2 距离矢量2 距离矢量 最大跳计数15 最大跳计数15 有类的 无类的 基于广播的    基于组播224.0.09 不支持VLSM 支持VLSM 无认证 允许MD5认证 不支持不 ...

  9. hdu1978(记忆化搜索)

    #include<iostream> #include<stdio.h> #include<string.h> #include<queue> usin ...

  10. ldap 使用 问题参考

    Q2.ldapsearch查询一个有30000多条记录时出现:Size limit exceeded 4 A2:服务器端配置文件有sizelimit 1000的限制!用管理员身份查询-D"c ...