江湖规矩,先%mmh
例①:P3812 【模板】线性基:
题目背景
这是一道模板题。
题目描述
给定n个整数(数字可能重复),求在这些数中选取任意个,使得他们的异或和最大。
输入格式
第一行一个数n,表示元素个数
接下来一行n个数
输出格式
仅一行,表示答案。
输入输出样例
输入 #1 复制
2
1 1
输出 #1 复制
1
说明/提示
1≤n≤50,0≤Si≤250
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
#include<cmath>
#define ll long long
#define llu unsigned ll
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
ll p[100];
void _insert(ll val)
{
for(int i=63;i>=0;i--)
{
if(val&(1ll<<i))
{
if(!p[i])
{
p[i]=val;
break;
}
else val^=p[i];
}
}
}
ll get_max(void)
{
ll ans=0;
for(int i=63;i>=0;i--)
{
if((ans^p[i])>ans) ans^=p[i];
}
return ans;
}
int main(void)
{
ll n,x;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
_insert(x);
}
printf("%lld\n",get_max());
return 0;
}
例② 异或第k小。
Libre OJ #114. k 大异或和:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
#include<cmath>
#define ll long long
#define llu unsigned ll
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
ll p[100],cnt;
ll np[100];
void _insert(ll val)
{
for(int i=63;i>=0;i--)
{
if(val&(1ll<<i))
{
if(!p[i])
{
p[i]=val;
break;
}
else val^=p[i];
}
}
}
//以下代码为求第k大异或值,其中cnt用于判断是否可以取到0
//cnt==n(数的个数)则不可以取到0,第k小就是第k小,否则第k小是第k-1小
void rebuild(void)
{
for(int i=63;i>=0;i--)
{
for(int j=i-1;j>=0;j--)
{
if(p[i]&(1ll<<j))
p[i]^=p[j];
}
}
for(int i=0;i<=63;i++)
{
if(p[i])
np[cnt++]=p[i];
}
}
ll get_kmin(ll k)
{
ll ans=0;
if(k>=(1ll<<cnt)) return -1;
for(int i=63;i>=0;i--)
if(k&(1ll<<i))
ans^=np[i];
return ans;
}
int main(void)
{
ll n,m,x,k;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
_insert(x);
}
rebuild();
int ff=0;
if(cnt!=n) ff=1;
scanf("%lld",&m);
for(int i=1;i<=m;i++)
{
scanf("%lld",&k);
printf("%lld\n",get_kmin(k-ff));
}
return 0;
}
还有另一种消元的线性基,思想一致,时间复杂度也是一样的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
#include<cmath>
#define ll long long
#define llu unsigned ll
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const int maxn=100010;
ll a[maxn],cnt;
void fi(ll n)
{
for(ll j=63;j>=0;j--)
{
ll k=0;
for(k=cnt+1;k<=n;k++)
if(a[k]&(1ll<<j)) break;
if(k>n) continue;
swap(a[k],a[++cnt]);
for(int i=1;i<=n;i++)
{
if(i!=cnt&&a[i]&(1ll<<j))
a[i]^=a[cnt];
}
}
}
ll get_kmin(ll k)
{
ll ans=0;
if(k>=(1ll<<cnt)) return -1;
for(int i=1;i<=cnt;i++)
if(k&(1ll<<(cnt-i)))
ans^=a[i];
return ans;
}
int main(void)
{
ll n,m,x,k;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
fi(n);
int ff=0;
if(cnt!=n) ff=1;
scanf("%lld",&m);
for(int i=1;i<=m;i++)
{
scanf("%lld",&k);
printf("%lld\n",get_kmin(k-ff));
}
return 0;
}