原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1601.html

题目传送门 - 51Nod1601

题意

题解

  首先我们考虑如何求答案。

  我们将所有数字按照二进制位从高到低建到 Trie 上,按照 kruscal 思想,我们要保证先选较小的边。

  于是我们很容易得出结论:在 Trie 上,设 $f(x) =$ 合并子树 $x$ 的所有叶子节点的代价,设 $L(x),R(x)$ 分别为 $x$ 的左右子树编号,则 $f(x)=f(L(x))+f(R(x))+Connect(L(x),R(x))$ 。其中 $Connect(a,b)$ 表示在 $a$ 的叶子节点中 和 $b$ 的叶子节点中各选择一个节点,并将他们相连,需要的最小代价。

  这个显然非常容易求。

  最后我们还有一个问题,就是当递归到 Trie 的叶子节点之后,我们发现它们代表的数字全部相同,连任意一条边的代价为 $0$ ,求把它们连成一棵树的方案,就相当于有 $k$ 个点的无根树计数。有一个东西叫做 pruffer 编码,通过这个东西可以得到 $k$ 个点的互不相同的带标号无根树个数为 $k^{k-2}$ 。

  于是问题就解决了。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005,S=N*30,mod=1e9+7;
LL read(){
LL x=0,f=1;
char ch=getchar();
while (!isdigit(ch)&&ch!='-')
ch=getchar();
if (ch=='-')
f=-1,ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+ch-48,ch=getchar();
return x*f;
}
int Next[S][2],tot[S],depth[S],flag[S],cnt=1;
int Pow(int x,int y){
int ans=1;
for (;y;y>>=1,x=1LL*x*x%mod)
if (y&1)
ans=1LL*ans*x%mod;
return ans;
}
LL ans1=0,ans2=1;
void build(int v){
int x=1,t;
for (int i=29;i>=0;i--){
t=(v>>i)&1;
if (!Next[x][t])
Next[x][t]=++cnt;
x=Next[x][t];
depth[x]=i,flag[x]=t;
}
tot[x]++;
}
int mindif,situ;
void Min_Cost_Merge(int x,int y,int dif){
dif|=(flag[x]^flag[y])<<depth[x];
int f=0;
for (int k=0;k<2;k++){
for (int t=0;t<2;t++)
if (Next[x][t]>0&&Next[y][t^k]>0)
Min_Cost_Merge(Next[x][t],Next[y][t^k],dif),f=1;
if (f)
return;
}
if (dif<mindif)
mindif=dif,situ=0;
if (dif==mindif)
situ=(1LL*tot[x]*tot[y]+situ)%mod;
}
int solve(int x){
if (!x)
return 0;
int s=solve(Next[x][0])+solve(Next[x][1]);
if (s==0&&tot[x]>1)
ans2=1LL*ans2*Pow(tot[x],tot[x]-2)%mod;
if (s==2){
mindif=1<<30,situ=1;
Min_Cost_Merge(Next[x][0],Next[x][1],0);
ans1+=mindif,ans2=1LL*ans2*situ%mod;
}
return 1;
}
int main(){
memset(tot,0,sizeof tot);
memset(Next,0,sizeof Next);
for (int i=1,n=read();i<=n;i++)
build(read());
solve(1);
printf("%lld\n%lld",ans1,ans2);
return 0;
}

  

51Nod1601 完全图的最小生成树计数 Trie Prufer编码的更多相关文章

  1. 51Nod1601 完全图的最小生成树计数

    传送门 我居然忘写题解啦!(记忆废) 不管怎么说,这题还算是一道好题啊……你觉得敦爷出的题会有水题么 …… 这题比较容易把人误导到Boruvka算法之类的东西上去(我们机房去刚D题的人一开始大多也被误 ...

  2. Luogu2290 [HNOI2004]树的计数 (组合计数,prufer编码)

    这不prufer编码吗,防爆long long就行了啊 #include <iostream> #include <cstdio> #include <cstring&g ...

  3. 「51Nod 1601」完全图的最小生成树计数 「Trie」

    题意 给定\(n\)个带权点,第\(i\)个点的权值为\(w_i\),任意两点间都有边,边权为两端点权的异或值,求最小生成树边权和,以及方案数\(\bmod 10^9 + 7\) \(n \leq 1 ...

  4. 51Nod 1601 完全图的最小生成树计数

    题目链接 分析: 这是一张完全图,并且边的权值是由点的权值$xor$得到的,所以我们考虑贪心的思想,考虑$kruskal$的过程选取最小的边把两个连通块合并,所以我们可以模仿$kruskal$的过程, ...

  5. 【BZOJ1211】树的计数(Prufer编码)

    题意:一个有n个结点的树,设它的结点分别为v1, v2, …, vn, 已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵. 其中1<=n<=150,输入数据保证满足条件的 ...

  6. 树的Prufer 编码和最小生成树计数

      Prufer数列 Prufer数列是无根树的一种数列.在组合数学中,Prufer数列由有一个对于顶点标过号的树转化来的数列,点数为n的树转化来的Prufer数列长度为n-2.它可以通过简单的迭代方 ...

  7. bzoj1211: [HNOI2004]树的计数 prufer编码

    题目链接 bzoj1211: [HNOI2004]树的计数 题解 prufer序 可重排列计数 代码 #include<bits/stdc++.h> using namespace std ...

  8. prufer编码

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

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

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

随机推荐

  1. OpenSIPS 1.11.1安装记录

    说明:操作系统Centos 6.5  64位 安装步骤: 1.安装依赖包 : yum -y install gcc make gdb wget yum -y install flex bison nc ...

  2. Django ----- 模板2

    tags for <ul> {% for user in user_list %} <li>{{ user.name }}</li> {% endfor %} #结 ...

  3. Django 笔记(三)模版路径 ~ 静态引用

    1.模版路径: 在 settings,py 里的 TEMPLATES = [] 内添加一句代码拼接路径 'DIRS': [os.path.join(BASE_DIR, 'templates')] 有两 ...

  4. 轻松搞懂elasticsearch概念

      本文主要介绍elasticsearch6.0的一些基本概念,有助于深入理解.研究elasticsearch和elk系统 一图胜千言 elasticsearch与mysql参照来看 添加一条数据 紫 ...

  5. git使用中出现的错误

    因同时有两个git账户,之前登录了git A 用户在使用了 1.       长期存储密码 git config --global credential.helper store 之后在git B 账 ...

  6. selenium之 chromedriver与chrome版本映射表(更新至v2.33)

    看到网上基本没有最新的chromedriver与chrome的对应关系表,便兴起整理了一份如下,希望对大家有用: chromedriver版本 支持的Chrome版本 v2.33 v60-62 v2. ...

  7. 第八单元 正文处理命令及tar命令

    使用cat命令进行文件的纵向合并  两种文件的纵向合并方法  归档文件和归档技术 归档的目的 什么是归档 tar命令的功能 tar命令的常用选项 使用tar命令创建.查看及抽取归档文件 使用tar命令 ...

  8. 前端之css样式(选择器)。。。

    一.css概述 CSS是Cascading Style Sheets的简称,中文称为层叠样式表,对html标签的渲染和布局 CSS 规则由两个主要的部分构成:选择器,以及一条或多条声明. 例如 二.c ...

  9. 《剑指offer》斐波那契数列

    本题来自<剑指offer> 斐波那契数列 矩阵覆盖 题目一: 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0).n<=39 思路: ...

  10. C++ Primer 笔记——固有的不可移植的特性

    1.为了支持底层编程,C++定义了一些固有的不可移植的特性,所谓不可移植特性是指因机器而异的特性. 2.一个位域中含有一定数量的二进制位,位域在内存中的布局是机器相关的.位域的类型必须是整型或枚举类型 ...