单纯异或问题
题目: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;
}
高斯消元代码:
待续