51Nod1601 完全图的最小生成树计数 Trie Prufer编码
原文链接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编码的更多相关文章
- 51Nod1601 完全图的最小生成树计数
传送门 我居然忘写题解啦!(记忆废) 不管怎么说,这题还算是一道好题啊……你觉得敦爷出的题会有水题么 …… 这题比较容易把人误导到Boruvka算法之类的东西上去(我们机房去刚D题的人一开始大多也被误 ...
- Luogu2290 [HNOI2004]树的计数 (组合计数,prufer编码)
这不prufer编码吗,防爆long long就行了啊 #include <iostream> #include <cstdio> #include <cstring&g ...
- 「51Nod 1601」完全图的最小生成树计数 「Trie」
题意 给定\(n\)个带权点,第\(i\)个点的权值为\(w_i\),任意两点间都有边,边权为两端点权的异或值,求最小生成树边权和,以及方案数\(\bmod 10^9 + 7\) \(n \leq 1 ...
- 51Nod 1601 完全图的最小生成树计数
题目链接 分析: 这是一张完全图,并且边的权值是由点的权值$xor$得到的,所以我们考虑贪心的思想,考虑$kruskal$的过程选取最小的边把两个连通块合并,所以我们可以模仿$kruskal$的过程, ...
- 【BZOJ1211】树的计数(Prufer编码)
题意:一个有n个结点的树,设它的结点分别为v1, v2, …, vn, 已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵. 其中1<=n<=150,输入数据保证满足条件的 ...
- 树的Prufer 编码和最小生成树计数
Prufer数列 Prufer数列是无根树的一种数列.在组合数学中,Prufer数列由有一个对于顶点标过号的树转化来的数列,点数为n的树转化来的Prufer数列长度为n-2.它可以通过简单的迭代方 ...
- bzoj1211: [HNOI2004]树的计数 prufer编码
题目链接 bzoj1211: [HNOI2004]树的计数 题解 prufer序 可重排列计数 代码 #include<bits/stdc++.h> using namespace std ...
- prufer编码
看51nod的一场比赛,发现不会大家都A的一道题,有关prufer的 我去年4月就埋下prufer这个坑,一直没解决 prufer编码是什么 对于一棵无根树的生成的序列,prufer序列可以和无根树一 ...
- [bzoj1005][HNOI2008]明明的烦恼-Prufer编码+高精度
Brief Description 给出标号为1到N的点,以及某些点最终的度数,允许在 任意两点间连线,可产生多少棵度数满足要求的树? Algorithm Design 结论题. 首先可以参考这篇文章 ...
随机推荐
- tcp和udp协议的聊天 和udp协议的时间同步机制-----编码
tcp协议聊天 服务端:: 客户端 udp协议的聊天 ############ udp协议 ########### 服务器 import socket sk = socket.socket(type ...
- LVM初级配置
步骤: 1.将物理硬盘转换成物理卷(PV) 创建PV:pvcreate /dev/vdb 2.将PV添加到卷组中(VG) vgcreate vg0 /dev/vdb 3.创建逻辑卷(LV)并从VG中调 ...
- JavaScript 加解密库(crypto-js)
1. 概述 1.1 说明 crypto-js(GitHub)是谷歌开发的一个纯JavaScript的加密算法类库,可以非常方便的在前端进行其所支持的加解密操作.目前crypto-js已支持的算法有:M ...
- WPF窗体的生命周期
和所有类一样,窗口也有生存期,在第一次实例化窗口时生存期开始,然后就可以显示.激活和停用窗口,直到最终关闭窗口. 1.显示窗体 构造函数 Show().ShowDialog()方法:Show()方法显 ...
- Swift 学习- 09 -- 枚举
// 递归枚举 // 美家居为一组相关的值定义了一个共同的类型, 使你可以在代码中以类型安全的的方式使用这些值. // 如果你熟悉C语言, 你会知道在C语言中, 枚举会为一组整型值分配相关联的名称, ...
- Oracle 数据库导入与出
Oracle 数据库导入与出 导出( EXPORT )是用 EXP 将数据库部分或全对象的结构和导出 . 导入( 导入( IMPORT )是用 )是用 IMP IMP将 OS 文件中的对象结构和数据装 ...
- centos7安装laravel
一. 安装前准备1. 安装screenyum install screen 2. 安装wgetyum install wget 3. 更新yumyum update 4. 安装额外资源库yum ins ...
- 论坛IP地址追踪&路由器密码嗅探
一.论坛IP地址查询 1.任何应用程序部可以调用一个标准的库函数来查看给定名称的主机IP地址.类似地,系统还提供一个逆函致—给定主机的IP地址,查看它所对应的主机名.大多数使用主机名作为参数的应用程序 ...
- cf861D 字典树+时间戳
好久没碰字典树之类的题了,搞起来有点生疏 /* 把所有母串的后缀加入字典树中 然后再扫一次所有母串的后缀,把后缀放到字典树中查询,找到第一个访问次数为1的结点返回即可 num在计数时,同一个母串的子串 ...
- Vue 添加外部的时间插件不触发v-model事件更改数据
使用的jquery日期插件 最终问题是 在选择完成日期后并未激活 oninput事件,所以也没有激活v-model 去改变date 解决思路: 去插件js文件中,在赋值给dom的时候添加模拟输入事件便 ...