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

来源:互联网 发布:妄想代理人知乎 编辑:程序博客网 时间:2024/05/22 00:25

题目描述

传送门

题解

挺好的一道思路题…
首先一条路径一定可以分解成一条简单路径和若干环的异或值
只需要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 1000005int n,m,x,y,acnt,bcnt,vis[N];int tot,point[N],nxt[N],v[N];LL c[N];LL z,h[N],mi[N],a[N],b[N],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);}
0 0
原创粉丝点击