异或问题整理(高斯消元留坑)

单纯异或问题

题目:https://www.nowcoder.com/acm/contest/15/B
题目描述:
给定一个长度为n的整数数组,问有多少对互不重叠的非空区间,使得两个区间内的数的异或和为0。
思路:前缀和

#include<bits/stdc++.h>
using namespace std;

const int N = 2e5+5;
int a[1005],x[N],cnt[N];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
        scanf("%d",&a[i]),x[i] = x[i-1]^a[i];
    long long sum = 0;
    for(int i = 1;i <= n;i++)
    {
        for(int j = i;j <= n;j++)
            sum += cnt[x[j] ^ x[i-1]];

        for(int j = 1;j <= i;j++)
            cnt[x[i] ^ x[j-1]]++;
    }
    printf("%lld\n",sum);
    return 0;
}

线段树维护位异或

题目:http://codeforces.com/gym/100739/problem/A
题意:给你一个数组,对数组进行单点修改,查询区间[L,R]内所有子区间的异或和。
思路:here

线性基&&高斯消元

线性基学习见ljh2000
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2460
题意:给你n矿石(序号+魔力值),让选一些矿石使得序号异或不为0且魔力值加和最大
思路:贪心+线性基/高斯消元
按魔力值排序,贪心取大魔力值

线性基代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1005;
struct node{
    ll num;
    int val;
    bool operator < (const node & p)const{
        return val > p.val;
    }
}a[N];
ll p[N];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
        scanf("%lld%d",&a[i].num,&a[i].val);
    sort(a+1,a+n+1);
    int ans = 0;
    for(int i = 1;i <= n;i++)
    {
        for(int j = 62;j >= 0;j--)
        {
            if(!(a[i].num >> j)) continue;
            if(!p[j]){
                p[j] = a[i].num;
                ans += a[i].val;
                break;
            }
            a[i].num ^= p[j];
        }
    }
    printf("%d\n",ans);
    return 0;
}

高斯消元代码:

暂时不会

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2115
题意:无向连通图( 图中可能有重边或自环),求1~n边权异或的最大值
思路:dfs + 线性基/高斯消元
dfs求1到点i异或值和一些环的异或值,然后求一个1到n异或值和一些环的异或的最大值
合理性:设4到1有两条路径path0,path1,如果我们选了path1,那么path0+path1为环,maxn = max(path1,path1^(path0+path1))
这个比较好理解

线性基代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 5e4 + 5;
const int M = 1e5 + 5;
int n,m,cnt,vis[N];
ll d[N],p[64],a[M*4];
struct node{
    int v;
    ll w;
};
vector<node> G[N];

void dfs(int u)
{
    vis[u] = 1;
    for(int i = 0;i < G[u].size();i++)
    {
        int v = G[u][i].v;ll w = G[u][i].w;
        if(!vis[v])
        {
            d[v] = d[u]^w;
            dfs(v);
        }
        else
            a[++cnt] = d[v]^d[u]^w;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int u,v;ll w;
    while(m--)
    {
        scanf("%d%d%lld",&u,&v,&w);
        G[u].push_back({v,w});
        G[v].push_back({u,w});
    }
    dfs(1);
    for(int i = 1;i <= cnt;i++)
    {
        for(int j = 62;j >= 0;j--)
        {
            if(!(a[i] >> j)) continue;
            if(!p[j]){
                p[j] = a[i];
                break;
            }
            a[i] ^= p[j];
        }
    }
    ll ans = d[n];
    for(int i = 62;i >= 0;i--)
        if((ans^p[i]) > ans)
            ans = ans ^ p[i];
    printf("%lld\n",ans);
    return 0;
}

高斯消元代码:

待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值