线性基在ACM中的应用

生成线性基:

void cal() {
    for (int i = 0; i < n; ++i)
        for (int j = MAX_BASE; j >= 0; --j)
            if (a[i] >> j & 1) {
                if (b[j]) a[i] ^= b[j];
                else {
                    b[j] = a[i];
                    for (int k = j - 1; k >= 0; --k) if (b[k] && (b[j] >> k & 1)) b[j] ^= b[k];
                    for (int k = j + 1; k <= MAX_BASE; ++k) if (b[k] >> j & 1) b[k] ^= b[j];
                    break;
                }
}


在这里插入图片描述

模板题

传送们:https://codeforces.com/problemsets/acmsguru/problem/99999/275
在这里插入图片描述
VJ 的 SGU 接口好像炸了,在 Codeforces 上找到了这道题。记得MAX_BASE要开在63,一开始WA因为MAX_BASE开小了。

#include <iostream>
#define LL long long 
using namespace std;
const int maxn=150,BASE=63;
LL a[maxn],b[maxn],n;
void cal(){
	for (int i=0;i<n;i++)
		for (int j = BASE;j>=0;--j)
			if (a[i] >> j & 1){
				if (b[j]) a[i]^=b[j];
				else {
					b[j] = a[i];
					for (int k=j-1;k>=0;--k) 
						if (b[k] && (b[j]>>k &1)) b[j]^= b[k];
					for (int k = j+1;k<=BASE;++k)
						if (b[k] >> j & 1) b[k]^=b[j];
					break;
				}
			}
}
int main(){
	cin >> n;	
	for (int i=0;i<n;i++) cin >> a[i];
	cal();
	LL ans=0;
	for (int i=0;i<=BASE;i++) //cout << b[i] <<' ',
		ans=ans^b[i];
	cout <<  ans;
}

在这里插入图片描述

区间异或和第k小

在这里插入图片描述
求第k小,把k用二进制编码,非常巧妙的标表达出第k小的数选择。在这里插入图片描述
原理比较好理解,关键是注意如果n=size的情况下放在一起可能可以取零,我们选择用一个 zero = n !=size 来标记。这是一开始 WA 的原因,可是写的跟标程自认为没啥区别了还是会 WA,于是直接粘一波标程吧。

//  HDOJ 3949 线性基
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
inline ll readLL() {
    static ll n;
    static int ch;
    n = 0, ch = getchar();
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) n = n * 10 + ch - '0', ch = getchar();
    return n;
}

const int MAX_N = 100000 + 3, MAX_BASE = 60;
int n, zero = false;
ll a[MAX_N], b[MAX_BASE + 3];
vector<ll> mmap;

void prepare() {
    int cnt = 0;
    memset(b, 0, sizeof b);
    for (int i = 0; i < n; ++i)
        for (int j = MAX_BASE; j >= 0; --j)
            if (a[i] >> j & 1) {
                if (b[j]) a[i] ^= b[j];
                else {
                    b[j] = a[i], cnt++;
                    for (int k = j - 1; k >= 0; --k) if (b[k] && ((b[j] >> k) & 1)) b[j] ^= b[k];
                    for (int k = j + 1; k <= MAX_BASE; ++k) if ((b[k] >> j) & 1) b[k] ^= b[j];
                    break;
                }
            }
    zero = cnt != n;

    mmap.clear();
    for (int i = 0; i <= MAX_BASE; ++i)
        if (b[i]) mmap.push_back(b[i]);
}

ll query(ll k) {
    if (zero) k--;
    if (k >= (1LL << (int)mmap.size())) return -1;
    ll ans = 0;
    for (int i = 0; i < (int)mmap.size(); ++i) if ((k >> i) & 1)
        ans ^= mmap[i];
    return ans;
}

int main() {
    int caseNum = readLL();
    for (int t = 1; t <= caseNum; ++t) {
        n = readLL();
        for (int i = 0; i < n; ++i) a[i] = readLL();

        prepare();

        printf("Case #%d:\n", t);
        int q = readLL();
        for (int i = 0; i < q; ++i) printf("%lld\n", query(readLL()));
    }
    return 0;
}

无向图1-n路径边上异或和最大

在这里插入图片描述
涉及到比较多的技巧。直接放上代码。

//  Created by Sengxian on 2016/12/05.
//  Copyright (c) 2016年 Sengxian. All rights reserved.
//  BZOJ 2115 线性基
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
inline ll readLL() {
    static ll n;
    static int ch;
    n = 0, ch = getchar();
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) n = n * 10 + ch - '0', ch = getchar();
    return n;
}

const int MAX_N = 50000 + 3, MAX_M = 100000 + 3, MAX_BASE = 60;
struct edge {
    edge *next, *rev;
    int to;
    ll cost;
    edge(edge *next = NULL, int to = 0, ll cost = 0): next(next), to(to), cost(cost) {}
} pool[MAX_M * 2], *pit = pool, *first[MAX_N];
int n, m, cnt = 0;
ll d[MAX_N], a[MAX_N + MAX_M * 2], b[MAX_BASE + 3];

void dfs(int u, edge *fa) {
    static bool vis[MAX_N];
    vis[u] = true;

    for (edge *e = first[u]; e; e = e->next) if (e->rev != fa) {
        if (!vis[e->to]) {
            d[e->to] = d[u] ^ e->cost;
            dfs(e->to, e);
        } else a[cnt++] = d[u] ^ d[e->to] ^ e->cost;
    }
}

void prepare() {
    for (int i = 0; i < cnt; ++i)
        for (int j = MAX_BASE; j >= 0; --j)
            if (a[i] >> j & 1) {
                if (b[j]) a[i] ^= b[j];
                else {
                    b[j] = a[i];
                    for (int k = j - 1; k >= 0; --k) if (b[k] && (b[j] >> k & 1)) b[j] ^= b[k];
                    for (int k = j + 1; k <= MAX_BASE; ++k) if (b[k] >> j & 1) b[k] ^= b[j];
                    break;
                }
            }
}

int main() {
    n = readLL(), m = readLL();
    for (int i = 0; i < m; ++i) {
        int u = readLL() - 1, v = readLL() - 1;
        ll w = readLL();
        first[u] = new (pit++) edge(first[u], v, w);
        first[v] = new (pit++) edge(first[v], u, w);
        first[u]->rev = first[v], first[v]->rev = first[u];
    }

    dfs(0, NULL);
    prepare();

    ll ans = d[n - 1];
    for (int i = MAX_BASE; i >= 0; --i)
        if (ans < (ans ^ b[i])) ans ^= b[i];

    printf("%lld\n", ans);
    return 0;
}

参考链接:https://blog.sengxian.com/algorithms/linear-basis

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值