BZOJ 2115 线性基

简略题意:你需要找到一条从 1 n的路径,使得这条路径上的亦或和最大。

这题和HDU5544本质相同。
首先考虑对于图上的一个环,那么从 1 走到环,然后回到1,这条路径的答案显然就是这个环的答案,因此预处理出每个环代表的数,就相当于从 n 个数选取k个数,使得答案的值尽可能变大。
不考虑环的话,我们随意找一条从 1 n的简单路径,当这条路径就是答案路径的时候,显然答案最大。如果我们找到的不是答案路径,显然这条路径和答案路径成了一个环,如果我们选取了这个环,就相当于我们只走了答案路径。
因此我们只需要找到任意从 1 n的路径,作为初始答案,随后问题就转化成了给定一个初始值,需要从 n 个数选取k个数,使得答案最大化。

#include <bits/stdc++.h>

using namespace std;

const double pi = acos(-1.0);
typedef long long LL;

const LL maxn = 55000;

/*
1. 找路径
2. 找环
3. 线性基
*/

LL n, m;
LL res1;
LL vis[maxn];
LL XOR[maxn];
vector<pair<LL, LL> > G[maxn];
vector<LL> ans;
LL a[64];

void init() {
    res1 = 0;
    for(LL i = 0; i < maxn; i++) G[i].clear();
}

LL sign;

void dfs1(LL u, LL dis) {
    if(sign) return ;
    vis[u] = 1;
    if(u == n) {
        sign = 1;
        res1 = dis;
//        cout<< dis <<" denig "<<endl;
        return ;
    }
    for(int i = 0; i < G[u].size(); i++) {
        pair<LL, LL> it = G[u][i];
        LL v = it.first, w = it.second;
        if(!vis[v]) {
            dfs1(v, dis ^ w);
        }
    }
}

void dfs(LL u, LL fa, LL dis) {
    if(vis[u]) {
        ans.push_back(XOR[u] ^ dis);
        return ;
    }
    XOR[u] = dis;
    vis[u] = 1;
    for(int i = 0; i < G[u].size(); i++) {
        pair<LL, LL> it = G[u][i];
        LL v = it.first, w = it.second;
        if(v == fa) continue;
        dfs(v, u, dis ^ w);
    }
}

void solve() {
    init();
    scanf("%lld%lld", &n, &m);
    for(LL i = 1; i <= m; i++) {
        LL u, v, w;
        scanf("%lld%lld%lld", &u, &v, &w);
        G[u].push_back({v, w});
        G[v].push_back({u, w});
    }
    sign = 0;
    memset(vis, 0, sizeof vis);
    dfs1(1, 0);

    ans.clear();
    memset(vis, 0, sizeof vis);
    memset(XOR, 0, sizeof XOR);
    dfs(1, -1, 0);

    memset(a, 0, sizeof a);
for(int i = 0; i < ans.size(); i++) {
    LL it = ans[i];
    for(int j = 62; j >= 0; j--) {
        if(it & (1LL << j)) {
            if(a[j]) it ^= a[j];
            else {
                a[j] = it;
                break;
            }
        }
    }
}
    for(int i = 62; i >= 0; i--)
        res1 = max(res1, res1^a[i]);
    printf("%lld\n", res1);
}

int main() {
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值