传送门

我居然忘写题解啦!(记忆废)

不管怎么说,这题还算是一道好题啊……你觉得敦爷出的题会有水题么

……

这题比较容易把人误导到Boruvka算法之类的东西上去(我们机房去刚D题的人一开始大多也被误导了),但仔细思考之后是可以发现问题的特殊性质的。

听说很多人是从Kruskal算法想到这道题的做法的?好吧我并不是,那我就写写我的思考过程好了……

记得算导上有一道思考题,判断一个最小生成树算法的正确性。那个算法是这样的:把当前图的点集随意划分成两半,递归两半后选出连接两个点集的边中权值最小的一条,得到最后的最小生成树。

这个算法显然是错的,因为最终的最小生成树中可能有两条连接当前层两个点集的边。但本题有特殊性,边权都是端点点权的异或值,也许可以把这个算法改造一下用到这道题中。

考虑对一个点集求最小生成树,由于边权是端点点权的异或,因此可以把所有点按照最高位划分成两半,一半最高位为0,另一半最高位为1。这样递归两半之后只选一条连接两半的最小权边就可以得到一个生成树。可以证明它是最小生成树,并且证明起来并不难:如果某一组解中有两条边都连接了两半,由于这两条边边权的最高位一定是1,而位于两半内的边边权最高位一定是0,因此把这两条边中的一条替换成两半内的边得到的解一定比当前优。

有了正确性,算法也就成型了:每次把当前点集按最高位划分为两半后递归两半,然后若两边均非空则把任意一条连接两半的最小权边加入最小生成树即可。可能有多条边都是最小权边,显然方案数应该是每层的方案数之积。

实现的时候对所有权值建一棵01-Trie,那么选边的过程就相当于对每个点计算它的左子树和右子树之间的贡献,再dfs一遍左右子树即可。每个数最多被dfs到$\frac{32^2}2=512$次,因此复杂度为$O(512n)$。

注意一个细节:在划分过程中如果递归到了叶子节点且此处点数$>1$,则说明有多个点权值相同,显然这些点随便连就行了,那么答案就应该乘上对应点数的无向完全图生成树的数量。这个在OEIS上可以找到,通项是$n^{n-2}$。

 #include<cstdio>
#include<cstring>
#include<cassert>
#include<algorithm>
using namespace std;
const int maxn=,maxm=maxn<<,p=1e9+;
void insert(int,int&);
void solve(int,int);
void dfs(int,int,int,int);
int qpow(int,int);
long long sum=;
int sm[maxm]={},ch[maxm][]={{}},root=,cnt=;
int n,a[maxn],x,ans=,mn,tmp;
signed main(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&x);
insert(,root);
}
solve(,root);
//assert(ans==1ll);
printf("%lld\n%d",sum,ans);
return ;
}
void insert(int k,int &rt){
if(!rt)rt=++cnt;
sm[rt]++;
if(k==-)return;
insert(k-,ch[rt][(x>>k)&]);
}
void solve(int k,int x){
if(sm[x]<=)return;//printf("solve(%d,%d)\n",k,x);
if(k==-){
ans=(long long)ans*qpow(sm[x],sm[x]-)%p;
return;
}
solve(k-,ch[x][]);
solve(k-,ch[x][]);
if(sm[ch[x][]]&&sm[ch[x][]]){
mn=;
tmp=;
dfs(k-,ch[x][],ch[x][],<<k);//printf("solve(%d,%d)\n",k,x);printf("mn=%d tmp=%d\n",mn,tmp);
sum+=mn;
ans=(long long)ans*tmp%p;
}
}
void dfs(int k,int x,int y,int now){
if(!sm[x]||!sm[y])return;
if(k==-){
if(now<mn){
mn=now;
tmp=(long long)sm[x]*sm[y]%p;
}
else if(now==mn)tmp=(tmp+(long long)sm[x]*sm[y]%p)%p;
return;
}
if(sm[ch[x][]]){
if(sm[ch[y][]])dfs(k-,ch[x][],ch[y][],now);
else dfs(k-,ch[x][],ch[y][],now|(<<k));
}
if(sm[ch[x][]]){
if(sm[ch[y][]])dfs(k-,ch[x][],ch[y][],now);
else dfs(k-,ch[x][],ch[y][],now|(<<k));
}
}
int qpow(int a,int b){
int ans=;
for(;b;b>>=,a=(long long)a*a%p)if(b&)ans=(long long)ans*a%p;
return ans;
}

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

  1. 51Nod1601 完全图的最小生成树计数 Trie Prufer编码

    原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1601.html 题目传送门 - 51Nod1601 题意 题解 首先我们考虑如何求答案. 我们将所有 ...

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

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

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

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

  4. 最小生成树计数 bzoj 1016

    最小生成树计数 (1s 128M) award [问题描述] 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一 ...

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

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

  6. 【bzoj1016】 JSOI2008—最小生成树计数

    http://www.lydsy.com/JudgeOnline/problem.php?id=1016 (题目链接) 题意 求图的最小生成树计数. Solution %了下题解,发现要写矩阵树,15 ...

  7. [BZOJ]1016 JSOI2008 最小生成树计数

    最小生成树计数 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同 ...

  8. bzoj1016 [JSOI2008]最小生成树计数

    1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3517  Solved: 1396[Submit][St ...

  9. 【BZOJ】【1016】【JSOI2008】最小生成树计数

    Kruskal/并查集+枚举 唉我还是too naive,orz Hzwer 一开始我是想:最小生成树删掉一条边,再加上一条边仍是最小生成树,那么这两条边权值必须相等,但我也可以去掉两条权值为1和3的 ...

随机推荐

  1. 51nod2004 终结之时 (支配树+树剖+树链的并)

    link 我永远喜欢洛天依 给定一张图世末积雨云,你需要维护其支配树: 单点修改,子树修改,树链修改 子树求和,树链求和,多条树链的并集求和 撤销之前的操作 可以先用 Lengauer-Tarjan ...

  2. HTML-JavaScript的DOM操作-非重点部分

    1.DOM的基本概念 DOM是文档对象模型,这种模型为树模型:文档是指标签文档(HTML文档),对象是指文档中每个元素:模型是指抽象划的东西. 2.Windows对象操作 一.属性和方法 属性(值或者 ...

  3. [原创]Redis 持久化说明及配置

    目录 参考链接 介绍 RDB 持久化 优点 缺点 相关配置参数 AOF 持久化 优点 缺点 相关配置参数 参考链接 持久化 Redis命令参考 介绍 Redis 运行时数据保存在内存中, 一旦重启则数 ...

  4. day0201

    #1.使用while循环输入 1 2 3 4 5 6 8 9 10'''count = 0while count < 10: count += 1 # count = count + 1 if ...

  5. 日志一直打印 DEBUG o.s.amqp.rabbit.listener.BlockingQueueConsumer

    <?xml version="1.0" encoding="UTF-8"?> <configuration> <logger na ...

  6. Watchbog挖矿病毒程序排查过程

    第1章 情况 1)服务器收到cpu报警,cpu被占用达到100%,登录服务器查看,发现cpu被一个watchbog的进程占满了,如下图所示: 2)并且无论如何都杀不掉,用kill杀掉后,其还是会隔一会 ...

  7. Ubuntu16.04+Cuda8.0+cuDNN6配置py-faster rcnn(转)

    原博客地址:https://blog.csdn.net/meccaendless/article/details/79557162 0前言Faster R-CNN是任少卿2015年底推出的目标检测算法 ...

  8. android 企业级高性能图表库 SciChart (付费)

    1.官网 https://www.scichart.com/ 2.特性 2.1 链接 https://www.scichart.com/android-chart-features/ https:// ...

  9. element-ui table多选CheckBox参数解析

    element-UI里的table表格与多选框CheckBox的组合很常用,官网也给了很多参数,自己总结了一下,方便日后使用 1.简易用法,没有附加的功能 要在表格里使用CheckBox很简单,只需设 ...

  10. python 库 、包 、模块

    概念: 模块: 模块是一种以.py为后缀的文件,在.py文件中定义了一些常量和函数.模块的名称是该.py文件的名称.模块的名称作为一个全局变量__name__的取值可以被其他模块获取或导入. 模块的导 ...