BZOJ1211:使用prufer编码解决限定结点度数的树的计数问题

首先学习一下prufer编码是干什么用的

prufer编码可以与无根树形成一一对应的关系

一种无根树就对应了一种prufer编码

先介绍编码过程:

选择无根树中度数为1的最小编号节点(也就是编号最小的叶子节点),将其删除,把它的邻接点加入数组

不断执行上述操作直到树中仅剩两个节点

解码过程:

顺序扫描prufer编码数组,将扫到的第一个节点记为节点u,寻找不在prufer编码中的没有被标记的最小编号的节点v

连接u-v并把v标记,将u从prufer编码数组删除并扫描下一个节点

性质:

一个点的入度为d,那么它最多有可能在prufer编码中出现d-1次

prufer编码一共有n-2个数字,每个相同的数字出现d-1次

针对这道题,如果我们给出了每个点的度数要求,那么满足要求的树的个数就是可生成的不同的prufer编码的个数:

(n - ) ! / ( (d1 - )! (d2 - )! ……(dn - )! ) 

这样就是答案了

下面介绍题目的实现方法(这个题比较简单,只是借助了prufer编码的性质进行计数,不涉及编码和解码的过程)

const int maxn=;
int n,tot,cnt;
int pri[maxn],d[maxn],num[maxn];
long long ans=;
long long s[];

tot用来统计prufer编码中应有的节点数,看是否满足等于n-2

cnt用来计数素数的个数,便于分解质因数

pri里存的的是每一个质数,num里存的是质数出现的次数

s用来预处理阶乘

抛开这道题,我们重点应该学一学这个分解质因数的方法

void solve(long long x,int f)  //按照指数分解质因数
{
for(int i=;i<=cnt;i++)
{
if(x<=) return;
while(x%pri[i]==) {num[i]+=f;x/=pri[i];}
}
}

满足题目的需求,直接计数即可:

    solve(s[n-],);  //计算阶乘并将结果分解质因数
for(int i=;i<=n;i++) solve(s[d[i]],-); //同上
for(int i=;i<=cnt;i++)
while(num[i]--) ans*=pri[i]; //统计结果
printf("%lld",ans);

下面给完整的代码:

 #include<cmath>
#include<cstdio>
const int maxn=;
int n,tot,cnt;
int pri[maxn],d[maxn],num[maxn];
long long ans=;
long long s[];
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>'') {if(ch=='-')f=-; ch=getchar();}
while(ch>=''&&ch<='') {x*=;x+=ch-'';ch=getchar();}
return x*f;
}
bool jud(int x)
{
for(int i=;i<=sqrt(x);i++)
if(x%i==) return ;
return ;
}
void getpri()
{
for(int i=;i<=;i++)
if(jud(i)) pri[++cnt]=i;
}
void solve(long long x,int f) //按照指数分解质因数
{
for(int i=;i<=cnt;i++)
{
if(x<=) return;
while(x%pri[i]==) {num[i]+=f;x/=pri[i];}
}
}
int main()
{
s[]=;
for(int i=;i<=;i++) s[i]=s[i-]*i;
getpri();
n=read();
if(n==)
{
int x=read();
if(x==) printf("");
else printf("");
return ;
}
for(int i=;i<=n;i++)
{
d[i]=read();
if(d[i]==) {printf("");return ;}
d[i]--;
tot+=d[i];
}
if(tot!=n-) {printf(""); return ;}
solve(s[n-],); //计算阶乘并将结果分解质因数
for(int i=;i<=n;i++) solve(s[d[i]],-); //同上
for(int i=;i<=cnt;i++)
while(num[i]--) ans*=pri[i]; //统计结果
printf("%lld",ans);
return ;
}

图论:Prufer编码的更多相关文章

  1. 图论:Prufer编码-Cayley定理

    BZOJ1430:运用Cayley定理解决树的形态统计问题 由Prufer编码可以引申出来一个定理:Cayley 内容是不同的n结点标号的树的数量为n^(n-2) 换一种说法就是一棵无根树,当知道结点 ...

  2. 树的prufer编码

    prufer是无根树的一种编码方式,一棵无根树和一个prufer编码唯一对应,也就是一棵树有唯一的prufer编码,而一个prufer编码对应一棵唯一的树. 第一部分:树编码成prufer序列. 树编 ...

  3. 【转】prufer编码

    既然有人提到了,就顺便学习一下吧,来源:http://greatkongxin.blog.163.com/blog/static/170097125201172483025666/ 一个含有n个点的完 ...

  4. [BZOJ1430] 小猴打架 (prufer编码)

    Description 一开始森林里面有N只互不相识的小猴子,它们经常打架,但打架的双方都必须不是好朋友.每次打完架后,打架的双方以及它们的好朋友就会互相认识,成为好朋友.经过N-1次打架之后,整个森 ...

  5. Codeforces 1109D. Sasha and Interesting Fact from Graph Theory 排列组合,Prufer编码

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF1109D.html 题意 所有边权都是 [1,m] 中的整数的所有 n 个点的树中,点 a 到点 b 的距离 ...

  6. prufer编码

    看51nod的一场比赛,发现不会大家都A的一道题,有关prufer的 我去年4月就埋下prufer这个坑,一直没解决 prufer编码是什么 对于一棵无根树的生成的序列,prufer序列可以和无根树一 ...

  7. [bzoj1005][HNOI2008]明明的烦恼-Prufer编码+高精度

    Brief Description 给出标号为1到N的点,以及某些点最终的度数,允许在 任意两点间连线,可产生多少棵度数满足要求的树? Algorithm Design 结论题. 首先可以参考这篇文章 ...

  8. BZOJ 1430 小猴打架(prufer编码)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1430 [题目大意] 一开始森林里面有N只互不相识的小猴子,它们经常打架, 但打架的双方 ...

  9. 【Foreign】树 [prufer编码][DP]

    树 Time Limit: 10 Sec  Memory Limit: 256 MB Description Input Output Sample Input 3 2 2 1 Sample Outp ...

随机推荐

  1. HDU 3007 Buried memory(计算几何の最小圆覆盖,模版题)

    Problem Description Each person had do something foolish along with his or her growth.But,when he or ...

  2. 蓝牙ble数据转语音实现Android AudioRecord方法推荐

    蓝牙ble数据转语音实现Android AudioRecord方法推荐 教程  欢迎走进zozo的学习之旅. 概述 蓝牙BLE又称bluetooth smart,主打的是低功耗和快速链接,所以在支持的 ...

  3. java — 重载和覆盖

    重载(overload):对于类的方法,方法名相同,参数列表不同的方法之间构成了重载关系. 参数列表:参数的类型.参数的个数.参数的顺序. 子类从父类继承来的方法也可以发生重载. 如果多个方法有相同的 ...

  4. iOS开发allocWithZone介绍

    首先我们知道,我们需要保证单例类只有一个唯一的实例,而平时我们在初始化一个对象的时候, [[Class alloc] init],其实是做了两件事. alloc 给对象分配内存空间,init是对对象的 ...

  5. 【Linux】- CentOS查看IP

    1.查询命令: ip addr 显示如图: 可以看到ens33没有inet这个属性,那么就没办法通过IP远程连接. 2.设置配置文件: vi /etc/sysconfig/network-script ...

  6. MVC绕过登陆界面验证时HttpContext.Current.User.Identity.Name取值为空问题解决方法

    Global.asax界面添加如下方法: void FormsAuthentication_Authenticate(object sender, FormsAuthenticationEventAr ...

  7. bzoj4502 串

    题意:给你n(n<=10000)个字符串,每个字符串的长度不超过30,可以选择两个非空前缀把它们拼起来得到一个字符串(这两个前缀可以来自同一个字符串,也可以是同一个字符串的同一个非空前缀),问得 ...

  8. 【刷题】BZOJ 4950 [Wf2017]Mission Improbable

    Description 那是春日里一个天气晴朗的好日子,你准备去见见你的老朋友Patrick,也是你之前的犯罪同伙.Patrick在编程竞赛上豪赌输掉了一大笔钱,所以他需要再干一票.为此他需要你的帮助 ...

  9. POJ3666:Making the Grade——题解

    http://poj.org/problem?id=3666 题目大意:给n个数,每次操作可使一个数+1或-1,求最小操作数使得序列不下降或不上升. —————————————————————— 思路 ...

  10. openjudge666:放苹果—题解

    (测试这里的markdown,同时也有纪念意义吧--第一次写的题解) 当时刚学递推的时候做的一道题 oj上的666题 666:放苹果 总时间限制: 1000ms 内存限制: 65536kB 描述 把M ...