线性基参考博客:
关于线性基的学习与理解
线性基详解
题目:P3812 【模板】线性基
题意:给你一个数组,让你任意选数,使异或和最大。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 100;
LL p[maxn];
void Insert(LL val){
for(int i = 55; i >= 0; i--){
if(val&(1ll<<i)){
if(p[i])val ^= p[i];
else {
p[i] = val;
break;
}
}
}
}
int main(){
int n;
LL v;
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%lld", &v);
Insert(v);
}
LL ans = 0;
for(int i = 55; i >= 0; i--){
if((ans^p[i]) > ans)ans ^= p[i];
}
printf("%lld\n", ans);
return 0;
}
题目:2460: [BeiJing2011]元素
题意:给你一个序列,每个序列有两个值,一个是序号,另外一个事价值,本题的题意是在序列中任选序列,使数列异或和不为0,并且价值最大。
思路:本题思路就是把序列从大到小排列一个顺序,然后就行现行基构造,在构造的过程中最终没有变为0,那么结果就加上这个价值。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100;
typedef long long LL;
pair<LL, LL>mp[1005];
LL p[maxn];
bool cmp(pair<LL, LL>a, pair<LL, LL>b){
return a.second > b.second;
}
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%lld %lld", &mp[i].first, &mp[i].second);
}
sort(mp, mp+n, cmp);
LL ans = 0;
//cout<<(1>>0&1)<<endl;
memset(p, 0, sizeof p);
for(int i = 0; i < n; i++){
LL v = mp[i].first;
for(int j = 63; j >= 0; j--){
if(v>>j&1){
if(p[j])v ^= p[j];
else {
p[j] = v;
ans += mp[i].second;
break;
}
}
}
}
printf("%lld\n", ans);
return 0;
}
题目:2115: [Wc2011] Xor
题意:就是给你一个图让你从1走到n的路径的最大异或和,存在重边和环。
思路:本题的思路就是随便走一条1~n的路,然后再把环加进去,有回到上面的类型题了。
参考博客:BZOJ2115 [Wc2011] Xor
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 1e5+10;
int h[maxn<<1], nex[maxn<<1], to[maxn<<1];
LL w[maxn<<1], p[100], vis[maxn], dis[maxn],circle[maxn<<1];
int tot = 0, cnt = 0, u, v;
LL val;
inline void add(int u, int v, LL val)//数组模拟链式前向星
{
to[tot] = v;
w[tot] = val;
nex[tot] = h[u];
h[u] = tot++;
}
inline void Insert(LL val)//线性基的构造
{
for(int i = 63; i >= 0; i-- )
{
if((val>>i)&1)
{
if(p[i])val ^= p[i];
else
{
p[i] = val;
break;
}
}
}
}
inline void dfs(int x)//搜索
{
vis[x] = 1;
for(int i = h[x]; ~i; i = nex[i])
{
int v = to[i];
LL val = w[i];
if(!vis[v])
{
dis[v] = dis[x]^val;//存储这个路径的异或和
dfs(v);
}
else
{
circle[cnt++] = dis[x]^dis[v]^val;//只保存环,所以异或上之前的点就把之前的异或和去掉,然后再异或上当前节点
}
}
}
int main()
{
int n, m;
tot = 0, cnt = 0;
scanf("%d %d", &n, &m);
memset(dis, 0, sizeof dis);
memset(h, -1, sizeof h);
for(int i = 1; i <= m; i++)
{
scanf("%d %d %lld", &u, &v, &val);
add(u, v, val);
add(v, u, val);
}
dfs(1);
LL ans = dis[n];
for(int i = 0; i < cnt; i++)
{
if(!circle[i])continue;
Insert(circle[i]);
}
for(int i = 63; i >= 0; i--)//找最大异或和
{
if((ans^p[i])>ans) ans ^= p[i];//注意(ans^p[i])>ans,一定要加括号,否就凉凉
}
printf("%lld\n", ans);
return 0;
}