高斯消元+线性基--bzoj2115

给一张无向图,求最大路径xor和
这道题必须写···神坑简直
是郭资政巨神讲的···
位之间会相互影响所以不能拆开分别放
找出一组环可表示图里所有路径
路径->基础路径^环集合
转化成给n个数求子集xor最大是多少
a b c 和a a^b c的表示能力是一样的
可以利用高斯消元的想法消成三角形
再将剩下的数异或起来
复杂度:
消元 O(64)枚举变量*O(n)消其余*O(1)消一个
嗯对就这样
但是里面要用到线性基
这个玩意比较玄
看到了一个比较好的讲线性基的blog
在这:
https://blog.csdn.net/qaq__qaq/article/details/53812883

但是呢还有一种不用线性基的
而且也非常好想
在下面代码里有

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 50005
#define M 200005
#define LL long long
using namespace std;
int n,m,head[N],cnt,pri,tot;
LL a[N],b[65],cir[M],ans;
bool vis[N];
struct node{
  int to,nxt;
  LL w;
}edge[M];

inline LL rd(){
  LL x=0,f=1; char c=' ';
  while(c<'0' || c>'9') {if(c=='-') f=-1;c=getchar();}
  while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
  return x*f;
}

void add(int x,int y,LL z){
  cnt++;
  edge[cnt].to=y;
  edge[cnt].nxt=head[x];
  edge[cnt].w=z;
  head[x]=cnt;
}

void dfs(int u){
  vis[u]=1;
  for(int i=head[u];i;i=edge[i].nxt){
    int v=edge[i].to;
    if(!vis[v]) a[v]=a[u]^edge[i].w,dfs(v);
    else cir[++tot]=a[v]^a[u]^edge[i].w;
  }
  return;
}

void Gauss(){
    for(int i=1;i<=tot;i++)//构造线性基 
        for(int j=62;j>=0;j--){
            if(!(cir[i]>>j)) continue;
            if(!b[j]) {b[j]=cir[i];break;}
            cir[i]^=b[j];
        }

    for(int i=62;i>=0;i--)
        ans=max(ans,ans^b[i]);
}
//还有一种和普通高斯消元很像的方法qwq很好理解,如下: 
/* 
void Gauss(){
    for(int i=1;i<=tot;i++){
        if(!cir[i]) continue;
        int tar=i;
        for(int j=i+1;j<=tot;j++){
            if(cir[j]>cir[tar]) tar=j;//找到最大的系数 
        }
        if(tar!=i) swap(cir[tar],cir[i]);
        int aim=0;
        LL x=cir[i];
        while(x){ //找到最高位的1 
            aim++;
            x>>=1;
        }
        aim--;//这个地方要减1的··· 
        for(int j=1;j<=tot;j++){
            if(j==i) continue;
            if(cir[j]&(1LL<<aim)) cir[j]^=cir[i]; //aim写成j wa了无数次,讲真样例真的水··写成啥样都能过 
        }//如果这个数的aim位有1就把它消掉 
    }
    for(int i=1;i<=tot;i++)
        ans=max(ans,ans^cir[i]);
} 
*/
int main(){
  n=rd(); m=rd();
  for(int i=1;i<=m;i++){
    int x=rd(),y=rd(); LL z=rd();
    add(x,y,z); add(y,x,z);
  }
  dfs(1);
  ans=a[n];//任取一条从1到n的路径,并得到其xor和 
  Gauss();
  printf("%lld\n",ans);
  return 0;
}

猜你喜欢

转载自blog.csdn.net/sizeof_you/article/details/80906067