您的位置:首页 > 其它

[BZOJ2115][Wc2011] Xor(dfs+高斯消元求线性基+贪心)

2017-01-13 21:48 369 查看

题目描述

传送门

题解

挺好的一道思路题…

首先一条路径一定可以分解成一条简单路径和若干环的异或值

只需要dfs一遍所有能dfs到的环,剩余的环都可以通过其它的环组合(异或)得到

而简单路径可以是任意一条,因为环不一定和简单路径只有一个公共点(画图…不过据说可以证明?)

所以,dfs出任意一条简单路径,再dfs出所有环(每一个点只访问一遍),问题转化为将若干环组合与简单路径的异或最大

对于环求线性无关组

然后贪心地从高位到低位枚举,对于不是1的某一位贪心地搞成1就行了…

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long
#define N 1000005

int n,m,x,y,acnt,bcnt,vis
;
int tot,point
,nxt
,v
;LL c
;
LL z,h
,mi
,a
,b
,road,ans;

void add(int x,int y,LL z)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
}
void dfs(int x)
{
if (x==n) road=h[x];
for (int i=point[x];i;i=nxt[i])
{
if (vis[v[i]])
{
LL t=h[x]^c[i]^h[v[i]];
if (t) a[++acnt]=t;
}
else
{
vis[v[i]]=1;
h[v[i]]=h[x]^c[i];
dfs(v[i]);
}
}
}
int main()
{
mi[0]=1LL;for (int i=1;i<=59;++i) mi[i]=mi[i-1]*2LL;
scanf("%d%d",&n,&m);
for (int i=1;i<=m;++i)
{
scanf("%d%d%lld",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
h[1]=0;vis[1]=1;dfs(1);
memset(vis,0,sizeof(vis));
for (int i=1;i<=acnt;++i)
for (int j=59;j>=0;--j)
if (a[i]&mi[j])
{
if (!vis[j])
{
vis[j]=i;
b[++bcnt]=a[i];
break;
}
else a[i]^=a[vis[j]];
}
sort(b+1,b+bcnt+1);
for (int i=1;i<bcnt;++i)
{
int bit=60;
for (int j=59;j>=0;--j)
if (b[i]&mi[j]) {bit=j;break;}
for (int j=i+1;j<=bcnt;++j)
if (b[j]&mi[bit]) b[j]^=b[i];
}
ans=road;
for (int i=bcnt;i>=1;--i)
{
int bit=60;
for (int j=59;j>=0;--j)
if (b[i]&mi[j]) {bit=j;break;}
if (ans&mi[bit]) continue;
ans^=b[i];
}
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: