mst
https://www.zybuluo.com/ysner/note/1245941
题面
给一个\(n\)点完全图,点权均小于\(2^m\)。定义边权等于两端点点权的与和(即\(a_i\&b_i\))。求最大生成树边权和。
- \(10pts\ n\leq8000\)
- \(15pts\ m=1\)
- \(25pts\ m\leq12\)
- \(55pts\ m\leq15\)
- \(90pts\ n\leq10^5,m\leq18\)
- \(100pts\ n\leq5*10^6,m\leq20\)
解析
\(10pts\)算法
用\(Kruskal\)搞复杂度为\(O(n^2logn)\),会\(TLE\)。
可以用\(O(n^2)\)的\(Prim\)算法。
for(rg int i=1;i<=n;i++) Dis[i]=-Inf;
Dis[1]=0; ll Ans=0;
for(rg int i=1;i<=n;i++)
{ int Now=0,Maxd=-Inf;
for(rg int j=1;j<=n;j++)
if(!Blue[j]&&Dis[j]>Maxd) Now=j,Maxd=Dis[j];
Ans+=Maxd,Blue[Now]=1;
for(rg int j=1;j<=n;j++)
if(!Blue[j]) Dis[j]=Max(Dis[j],A[Now]&A[j]);
}
值得注意的是初始值极小,永远在取\(\max\)。
\(15pts\)算法
说明点权只能为\(0\)或\(1\)。
\(x\)个\(1\)点最多能连\(x-1\)条边。
\(ans=x-1\)。
\(25pts\)算法
注意到如果数值\(p\)重复出现\(x\)次,答案加上\((x-1)*p\)(相同数值相互连边)后,就可把该数值视为唯一。
于是\(n\)降到\(O(2^{12})=4096\),又可以\(Prim\)啦。
\(55pts\)算法
注意到若\(a\&b=b\),在\((a,b)\)间连边一定最优。于是可以找出每个点\(b\)的子集(复杂度\(O(15n)\)),若存在,优先建边并统计答案。
然后由于剩下点互不包含,点数会降到\(C_m^{m/2}\)(因为最多的情况是选所有有\(m/2\)个\(1\)的二进制数,而这些数因为\(1\)数量相同,肯定互不包含),似乎又可以暴力了。
\(90pts\)算法
这个算法很神仙。
论如何求集合中选一个数与当前值进行位运算的\(\max\)。
(当然先\(orz\)CJrank1yyb)
如果是暴力的话,我们的方法有两种:
- 对于当前数\(x\),暴力计算所有存在的数\(a_i\)中,\(x\bigoplus i\)的最大值,这样的复杂度是\(O(2^{16})\)。
- 对于每个可能出现的数维护一个当前所有数的最大值。即每次插入时,暴力计算所有的答案的最大值,这样子询问的时候可以\(O(1)\)查询。
两种方法一种是插入\(O(1)\),询问\(O(n)\),另外一个是插入\(O(n)\),询问\(O(1)\)。
我们把两种东西结合一下,这样可以得到一个\(O(n\sqrt{n})\)的方法。
我们对于每个数从中间分开,拆成前\(8\)个二进制位和后\(8\)个二进制位。
这样子我们可以预处理一个数组\(t[i][j]\),
表示集合中一个前\(8\)位是\(i\)的数,后\(8\)位与\(j\)进行位运算的最大值。
因为位运算是可以按位贪心的,所以对于查询一个数\(x\),我们把它拆成\(x=a×2^8+b\)。
每次先暴力\(for\)所有可能的前\(8\)位,找到与\(a\)能够构成最大值的那些数,然后对于找到的所有数的前八位\(p\),直接查\(t[p][b]\)。
因为前八位更大的数一定更大,那么影响结果的就只剩下后八位了,
把两个部分拼接起来就好了。
这样子暴力\(for\)前八位的复杂度是\(O(2^8)\),查找后面部分最大值的复杂度是\(O(1)\)
所以这样子总的复杂度\(O(2^8)\)。
而对于集合中插入一个数,前\(8\)位唯一确定,每次只需要预处理后\(8\)位的结果。
时间复杂度还是\(O(2^8)\),总的复杂度还是\(O(\sqrt{n})\)。
最后记得反过来再跑一遍。
照搬该方法到本题,复杂度为\(O(n\sqrt{n})\)。
注意一下连边。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int mod=1e9+7,N=1e5+100;
int a[N],h[N],cnt,n,m,k,f[N],p=1,base,nxt[N],t[1<<11][1<<11],c[1<<11][1<<11],cp[N],tl[N],ma[N],fa[N];
ll ans;
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il int find(re int x){return fa[x]?fa[x]=find(fa[x]):x;}
il void link(re int u,re int v)
{
re int fu=find(u),fv=find(v);
if(fu^fv)
{
nxt[tl[fv]]=h[fu];
tl[fv]=tl[fu];
fa[fu]=fv;
++p;
}
}
il void solve()
{
memset(f,0,sizeof(f));memset(t,-1,sizeof(t));memset(ma,-1,sizeof(ma));
fp(i,1,n)
if(!fa[i])
{
for(re int j=h[i];j;j=nxt[j])
{
re int x=a[j]>>k,y=a[j]&base;//x代表前一半位,y代表后一半位
fp(z,0,(1<<m-k)-1)//枚举前一半位并统计答案
if(f[z])
{
re int ss=a[j]&t[z][y]|(z<<k&a[j]);//组合
if(ss>ma[i]) ma[i]=ss,cp[i]=c[z][y];
}
}
for(re int j=h[i];j;j=nxt[j])
{
re int x=a[j]>>k,y=a[j]&base;f[x]=1;//标记其存在
fp(z,0,(1<<k)-1)//枚举后一半位并处理
if((y&z)>t[x][z]) t[x][z]=y&z,c[x][z]=i;
}
}
memset(f,0,sizeof(f));memset(t,0,sizeof(t));
fq(i,n,1)
if(!fa[i])
{
for(re int j=h[i];j;j=nxt[j])
{
re int x=a[j]>>k,y=a[j]&base;
fp(z,0,(1<<m-k)-1)
if(f[z])
{
re int ss=a[j]&t[z][y]|(z<<k&a[j]);
if(ss>ma[i]) ma[i]=ss,cp[i]=c[z][y];
}
}
for(re int j=h[i];j;j=nxt[j])
{
re int x=a[j]>>k,y=a[j]&base;f[x]=1;
fp(z,0,(1<<k)-1)
if((y&z)>t[x][z]) t[x][z]=y&z,c[x][z]=i;
}
}
fp(i,1,n)
if(!fa[i])
{
re int u=find(i),v=find(cp[i]);
if(u^v) ans+=ma[i],link(i,cp[i]);
}
}
int main()
{
freopen("mst.in","r",stdin);
freopen("mst.out","w",stdout);
n=gi();m=gi();k=m/2;base=(1<<k)-1;
fp(i,1,n)
{
a[i]=gi();
h[i]=tl[i]=i;
}
while(p<n) solve();
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
\(100pts\)算法
倒序枚举用于连接的边权\(p\),用\(a_p\)表示\(p\)的最大超集(只多一个\(1\))所在联通块的代表元。枚举\(p\)的另一超集(只多一个\(1\)),若两者不在同一联通块,合并之。从大到小保证最优性。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int mod=1e9+7,N=1e5+100;
int a[1<<21],h[N],cnt,n,m,f[1<<21];
ll ans;
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il int find(re int x){return f[x]?f[x]=find(f[x]):x;}
int main()
{
freopen("mst.in","r",stdin);
freopen("mst.out","w",stdout);
n=gi();m=gi();
fp(i,1,n)
{
re int x=gi();
if(a[x]) ans+=x;
a[x]=x;
}
fq(t,(1<<m)-1,0)
{
re int &u=a[t];
for(re int i=0;!u&&i<m;i++) u=a[t|(1<<i)];
if(!u) continue;
fp(i,0,m-1)
{
re int v=a[t|(1<<i)],fu=find(u),fv=find(v);
if(v&&fu!=fv) ans+=t,f[fv]=fu;
}
}
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
mst的更多相关文章
- POJ1679 The Unique MST[次小生成树]
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 28673 Accepted: 10239 ...
- 基于MST的立体匹配及相关改进(A Non-Local Cost Aggregation Method for Stereo Matching)
怀着很纠结的心情来总结这篇论文,这主要是因为作者提虽然供了源代码,但是我并没有仔细去深究他的code,只是把他的算法加进了自己的项目.希望以后有时间能把MST这一结构自己编程实现!! 论文题目是基于非 ...
- BZOJ 2654 & 玄学二分+MST
题意: 给一张图,边带权且带颜色黑白,求出一棵至少包含k条白边的MST SOL: 正常人都想优先加黑边或者是白边,我也是这么想的...你看先用白边搞一棵k条边的MST...然后维护比较黑边跟白边像堆一 ...
- LA 5713 秦始皇修路 MST
题目链接:http://vjudge.net/contest/144221#problem/A 题意: 秦朝有n个城市,需要修建一些道路使得任意两个城市之间都可以连通.道士徐福声称他可以用法术修路,不 ...
- [poj1679]The Unique MST(最小生成树)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 28207 Accepted: 10073 ...
- [BZOJ2654]tree(二分+MST)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2654 分析:此题很奇葩,我们可以给所有白边加上一个权值mid,那么在求得的MST中白边 ...
- CodeForces 125E MST Company
E. MST Company time limit per test 8 seconds memory limit per test 256 megabytes input standard inpu ...
- 2015baidu复赛2 连接的管道(mst && 优先队列prim)
连接的管道 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- ACM/ICPC 之 判别MST唯一性-Kruskal解法(POJ1679)
判别MST是否唯一的例题. POJ1679-The Unique MST 题意:给定图,求MST(最小生成树)是否唯一,唯一输出路径长,否则输出Not Unique! 题解:MST是否唯一取决于是否有 ...
- hdu 4756 MST+树形dp ****
题意:给你n(n = 1000)个二维点,第一个点是power plant,还有n - 1个点是dormitories.然后现在知道有一条寝室到寝室的边是不能连的,但是我们不知道是哪条边,问这种情况下 ...
随机推荐
- ruby学习之路(一)
学习ruby最好的方法就是下载源码包,里面带有sample和test,是入门学习的最好实例. 我下载的是2.1.0版本,首先./configure,然后make,sudo make install.从 ...
- Luogu P1692 部落卫队
解题思路 数据范围不是很大,那应该不是那些普遍的图论的算法.考虑搜索,用暴力解决.从1到N枚举每一个点的位置,搜索这个点事选还是不选.如果在这个点之前选到的点中又和他冲突的点,那就不选,要么就选. 附 ...
- MySQL异常:com.mysql.jdbc.PacketTooBigException: Packet for query is too large
### Cause: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1169 > 1024). You ...
- Struts2学习笔记:DMI,多个配置文件,默认Action,后缀
动态方法调用有三种方法: 1.同一Action多次映射,每个action标签的method对应要调用的方法. 当要调用的方法多了就会增加struts.xml文件的复杂性. 2.struts.Dynam ...
- [bzoj1004][HNOI2008][Cards] (置换群+Burnside引理+动态规划)
Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红 ...
- ds020507
芯片输出端不加负载的时候,芯片的输出电压是9点多伏. 加上大的负载,芯片发热,电压接近输入电压. 正常负载,芯片输出7.0几伏. 版权声明:本文为博主原创文章,未经博主允许不得转载.
- Java Web学习总结(32)——Java程序员最亲睐的Web框架
这一次,我们要讨论的是web框架. 只有少数几种语言像Java一样提供了各种各样的web框架,上面的统计图就是一个证据.下面是其他开发者所使用web框架列表: spring MVC/Spring Bo ...
- noip模拟赛 三角形
[问题描述] 平面上有N条直线,用方程Aix + Biy +Ci =0表示.这些直线没有三线共点的.现在要你计算出用这些直线可以构造出多少三角形? 输入: 第1行:一个整数N(1 ≤ N≤ 30000 ...
- 稍微成型点的用WEBSOCKET实现的实时日志LOG输出
难的是还是就地用JS显示出来相关的发布进度. 还好,花了一下午实现了. 可以移植到项目中去罗... websocket.py: import tornado.ioloop import tornado ...
- MYSQL常用的时间日期函数
#时间日期函数 #获取当前日期XXXX-XX-XXSELECT CURRENT_DATE(); SELECT CURDATE();#效果与上一条相同 #获取当前日期与时间XXXX-XX-XX XX:X ...