两道题目大意都是根据每个点的度数来构建一棵无根树来确定有多少种构建方法

这里构建无根树要用到的是prufer序列的知识

先很无耻地抄袭了一段百度百科中的prufer序列的知识:

将树转化成Prufer数列的方法

一种生成Prufer序列的方法是迭代删点,直到原图仅剩两个点。对于一棵顶点已经经过编号的树T,顶点的编号为{1,2,...,n},在第i步时,移去所有叶子节点(度为1的顶点)中标号最小的顶点和相连的边,并把与它相邻的点的编号加入Prufer序列中,重复以上步骤直到原图仅剩2个顶点。
例子
Prufer数列

以右边的树为例子,首先在所有叶子节点中编号最小的点是2,和它相邻的点的编号是3,将3加入序列并删除编号为2的点。接下来删除的点是4,5被加入序列,然后删除5,1被加入序列,1被删除,3被加入序列,此时原图仅剩两个点(即3和6),Prufer序列构建完成,为{3,5,1,3}

将Prufer数列转化成树的方法

设{a1,a2,..an-2}为一棵有n个节点的树的Prufer序列,另建一个集合G含有元素{1..n},找出集合中最小的未在Prufer序列中出现过的数,将该点与Prufer序列中首项连一条边,并将该点和Prufer序列首项删除,重复操作n-2次,将集合中剩余的两个点之间连边即可。
例子
仍为上面的树,Prufer序列为{3,5,1,3},开始时G={1,2,3,4,5,6},未出现的编号最小的点是2,将2和3连边,并删去Prufer序列首项和G中的2。接下来连的边为{4,5},{1,5},{1,3},此时集合G中仅剩3和6,在3和6之间连边,原树恢复
 
这样很容易可以发现通过构建n-2个数的数列就可以得到唯一的一棵无根树,当然如果要求根的不同的话,那么在种数的基础上乘以n就行了嘛,反正每个点都是能作为根的
仔细观察数列很容易发现,构建数列的过程中每次删除的都是度数为1的点,放入父亲,那就有点像拓扑排序的过程了
而最后留了两个数,也可以理解为从prufer序列中删除,那么删除的点都减少了一个度数,其他度数有多少都放进了prufer序列中
那么就说明prufer序列中某一个点出现的次数就是它本身的度数减1
再从父亲到儿子的角度思考的话,因为prufer序列有n-2个点,但树有n-1条边,最后一条边也删去的话,最后加入序列末尾的必然是最大值n
那么这个时候我们可以把整个图看作是以n为根的树,出现在prufer序列中的点的次数就是它在树上含有的儿子个数
 
 
对于这两道题目的计算来说的话,就相当于将能构成树的这些树进行全排列,得到排列的方法数就行了
(n-2)! / (w[1]!*w[2]!*w[3]!...) w[i]表示 i 的度数-1
这种题目需要注意到无法构建树的情况即可
 
 #include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
#define pii pair<int,int>
int n , w[] , num[];
vector<pii> v[]; void solve(int m)
{
if(m==) return;
int tmp = m;
for(int i= ; i<=m ; i++){
if(m%i==){
int cnt = ;
while(m%i==){
m/=i;
cnt++;
}
v[tmp].push_back(make_pair(i , cnt));
}
}
if(m>) v[tmp].push_back(make_pair(m , ));
// for(int i=0 ; i<v[tmp].size() ; i++) cout<<v[tmp][i].first<<" "<<v[tmp][i].second<<endl;
}
void init()
{
for(int i= ; i<= ; i++) solve(i);
}
void update(int k , int flag)
{
for(int i= ; i<v[k].size() ; i++){
pii u=v[k][i];
num[u.first]+=u.second*flag;
}
}
void mul(long long &ans , int k , int tim)
{
for(int i= ; i<=tim ; i++) ans=ans*k;
}
int main()
{
// freopen("Sweet.in" , "r" , stdin);
init();
while(~scanf("%d" , &n)){
memset(num , , sizeof(num));
int sum= , flag=true;
for(int i= ; i<=n ; i++){
scanf("%d" , &w[i]);
if(w[i]==) flag = false;
sum+=w[i]-;
for(int j= ; j<=w[i]- ; j++) update(j , -);
}
if(n== && w[]==){
cout<<<<endl;
continue;
}
if(sum!=n- || n== || flag==false){
cout<<<<endl;
continue;
}
for(int i= ; i<=n- ; i++) update(i , );
long long ans = ;
for(int i= ; i<=n- ; i++){
if(num[i]) mul(ans , i , num[i]);
}
cout<<ans<<endl;
}
return ;
}

bzoj1211

 
 #include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define N 1005
int n , a[N] , cnt[N];
int ans[N*] , l1;
int mul[N] , l2;
int tmp[N*]; void fenjie(int x , int flag)
{
for(int i= ; i*i<=x ; i++){
while(x%i==){
cnt[i]+=flag;
x/=i;
}
}
if(x>) cnt[x]+=flag;
} void solveC(int a , int b) //C(n-2 , sum)
{
for(int i= ; i<=b ; i++) fenjie(i , -);
for(int i=a ; i>a-b ; i--) fenjie(i , );
} void change(int x)
{
l2 = ;
while(x){
mul[l2++] = x%;
x/=;
}
} void cal()
{
memset(tmp , , sizeof(tmp));
int len = ;
for(int i= ; i<l2 ; i++){
for(int j= ; j<l1 ; j++){
int cur = i+j;
len = max(len , cur+);
tmp[cur] += ans[j]*mul[i];
}
}
for(int i= ; i<len ; i++){
if(tmp[i]>=){
len= max(len , i+);
tmp[i+] += tmp[i]/;
tmp[i] %= ;
}
}
for(int i= ; i<len ; i++) ans[i] = tmp[i] , l1 = len;
} void print()
{
for(int i=l1- ; i>= ; i--) printf("%d" , ans[i]);
printf("\n");
}
int main()
{
// freopen("a.in" , "r" , stdin);
while(~scanf("%d" , &n)){
memset(cnt , , sizeof(cnt));
int w = , sum = ;
bool flag = true;
for(int i= ; i<=n ; i++){
scanf("%d" , &a[i]);
if(a[i]==) flag=false;
if(a[i]<) w++;
else{
sum+=a[i]-;
for(int j= ; j<=a[i]- ; j++) fenjie(j , -);
}
}
if(n== && a[]==){
cout<<<<endl;
continue;
}
solveC(n- , sum);
if(n== || sum>n- || flag==false) cout<<<<endl;
else{
for(int i= ; i<=sum ; i++) fenjie(i, );
int cnt = n--sum;
for(int i= ; i<=cnt ; i++) fenjie(w , );
}
// for(int i=1 ; i<=10 ; i++) cnt[i]++;
ans[] = , l1=;
for(int i= ; i<=n ; i++){
if(cnt[i]){
change(i);
for(int j= ; j<=cnt[i] ; j++){
cal();
}
}
}
print();
}
return ;
}

bzoj1005

bzoj 1005 1211 prufer序列总结的更多相关文章

  1. [HNOI2004]树的计数 BZOJ 1211 prufer序列

    题目描述 输入输出格式 输入格式: 输入文件第一行是一个正整数n,表示树有n个结点.第二行有n个数,第i个数表示di,即树的第i个结点的度数.其中1<=n<=150,输入数据保证满足条件的 ...

  2. [BZOJ1005][HNOI2008]明明的烦恼 数学+prufer序列+高精度

    #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int N; ...

  3. 【BZOJ 1211】 1211: [HNOI2004]树的计数 (prufer序列、计数)

    1211: [HNOI2004]树的计数 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2468  Solved: 868 Description 一 ...

  4. [HNOI2008][bzoj 1005]明明的烦恼(prufer序列)

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

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

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

  6. BZOJ 1005 明明的烦恼(prufer序列+高精度)

    有一种东西叫树的prufer序列,一个树的与一个prufer序列是一一对应的关系. 设有m个度数确定的点,这些点的度为dee[i],那么每个点在prufer序列中出现了dee[i]-1次. 由排列组合 ...

  7. BZOJ 1005 明明的烦恼 Prufer序列+组合数学+高精度

    题目大意:给定一棵n个节点的树的节点的度数.当中一些度数无限制,求能够生成多少种树 Prufer序列 把一棵树进行下面操作: 1.找到编号最小的叶节点.删除这个节点,然后与这个叶节点相连的点计入序列 ...

  8. BZOJ 1005 prufer序列

    给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? 第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di ...

  9. bzoj 1005: [HNOI2008]明明的烦恼 prufer编号&&生成树计数

    1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2248  Solved: 898[Submit][Statu ...

随机推荐

  1. 夺命雷公狗-----React---13--事件监听

    在react中事件监听直接作为组建的属性来添加即可,就像DOM中的html操作 <!DOCTYPE> <html> <head> <meta charset= ...

  2. 17. 星际争霸之php设计模式--职责链模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  3. 在linux中安装adb和fastboot工具

    我用的是archlinux,在官方的软件仓库里就可以找到对应的包,包的名字叫:android-tools 据说debian系列的软件包是两个,分别是:android-tools-adb, androi ...

  4. 【实践】jQuery实现三联联动

    网上看过很多关于联动的jq或js代码,最近班上的前端大神教了我一种比网上还简单的jq联动方法,自己琢磨过之后确实比其他方法更简单更简洁所以在这里分享一下 先上html代码 <div id=&qu ...

  5. Excel 统计在某个区间内数值的个数

    =COUNTIF(A1:A50,"<=1.0E-5")-COUNTIF(A1:A50,"<60")

  6. Java多线程之Lock的使用

    import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util ...

  7. 打包app命令行

    $ cd myApp $ ionic platform add android $ ionic build android $ ionic emulate android

  8. python(六)内置函数

    一.函数知识补充 函数不设置值,默认返回None:函数中参数都是按引用传递,函数里修改了参数,原始参数也会修改. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1 ...

  9. Intellij 图标介绍及配置文件常识

    图标 参数名称   含义 默认值   -Xms 初始堆大小 物理内存的1/64(<1GB) 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xm ...

  10. PHP下拉框内容随单选框内容变化

    这久在修改一个项目的小东西,要求把下拉框改为单选框,由于代码封闭,修改不了获取函数,所以想了个办法让下拉框的内容随单选框的内容变化,下面把代码分享给大家: <!DOCTYPE html PUBL ...