BZOJ 2115 [Wc2011] Xor 高斯消元

题意:链接

方法:高斯消元

解析:不怎么好想的一道题,不过如果想到的话那就是水题一个了。

首先明确一些概念

简单路径:顶点序列中顶点不重复出现的路径。

简单环:在一个回路中,若除第一个与最后一个顶点外,其余顶点不重复出现的回路称为简单回路(简单回路)。

然后呢明确题里说的是什么?

找一条1到n的路径使得所有路径上的边权异或和最大。

那么我们可以拆分一下,这条1到n的路径我们看做两个部分组成:一条简单路径从1到n,以及任意简单环。

这样就比较明了了,然后我们发现,这个简单路径其实找一条就可以了,由一个数异或同一个数两次则不改变这个数这条性质,我们可以知道,其实找到的1到n的路径任意的添加简单环就会成为不同的1到n的路径,也就是说我们可以找到一个基准简单路径异或值。然后我们预处理出所有简单环的异或和。将这道题完美的转化为n个环的异或和已知,现有一个定值m,在这n个数中选择任意个数对m进行异或使得最终的m最大。

这一看我们转化的东西,那就是高斯消元解异或方程组啊,直接水。

不过高斯消元还是调了一阵!!

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 50010
#define M 100100
using namespace std;
typedef long long ll;
int n,m,cnt,tot;
struct node
{
    int to,next;
    ll val;
}edge[M<<1];
int head[N];
int vis[N];
ll dis[N];
ll circle[M<<1];
void init()
{
    memset(head,-1,sizeof(head));
    cnt=1;
}
void edgeadd(int from,int to,ll val)
{
    edge[cnt].to=to,edge[cnt].val=val;
    edge[cnt].next=head[from];
    head[from]=cnt++;
}
void dfs(int now)
{
    vis[now]=1;
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(vis[to])
        {
            if(!(dis[now]^dis[to]^edge[i].val))continue;
            circle[++tot]=dis[now]^dis[to]^edge[i].val;
        }else
        {
            dis[to]=dis[now]^edge[i].val;
            dfs(to);
        }
    }
}
void gauss()
{
    int flag=1,j;
    for(ll i=(1ll<<62);i;i>>=1)
    {
        for(j=flag;j<=tot;j++)
        {
            if(circle[j]&i)break; 
        }
        if(j==tot+1)continue;
        swap(circle[flag],circle[j]);
        flag++;
        for(int k=1;k<=tot;k++)
        {
            if(k==flag-1)continue;
            if(circle[k]&i)circle[k]^=circle[flag-1];
        }
    }
}
int main()
{
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        ll val;
        scanf("%d%d%lld",&x,&y,&val);
        edgeadd(x,y,val);
        edgeadd(y,x,val);
    }
    dfs(1);
    gauss();
    for(int i=1;i<=tot;i++)
    {
        if((circle[i]^dis[n])>dis[n])dis[n]^=circle[i];
    }
    printf("%lld\n",dis[n]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值