定义:
基:在线性代数中,基(也称为基底)是描述、刻画向量空间的基本工具。向量空间的基是它的一个特殊的子集,基的元素称为基向量。向量空间中任意一个元素,都可以唯一地表示成基向量的线性组合。如果基中元素个数有限,就称向量空间为有限维向量空间,将元素的个数称作向量空间的维数。
同样的,线性基是一种特殊的基,它通常会在异或运算中出现,它的意义是:通过原集合S的某一个最小子集S1使得S1内元素相互异或得到的值域与原集合S相互异或得到的值域相同。
线性基的性质:
原序列里面的任意一个数都可以由线性基里面的一些数异或得到。
线性基里面的任意一些数异或起来都不能得到0。
线性基里面的数的个数唯一,并且在保持性质一的前提下,数的个数是最少的。
具体的构成可以去查看向量组的相关性!!!!!
构造线性基:保证线性基的元素满足以上的性质
void insert_num(int x)///初始线性基
{
for(int i=61; i>=0; i--)
{
if(x&1ll<<i)
{
if(dp[i])
x^=dp[i];///保证每个位置元素的唯一性
else
{
dp[i]=x;
break;
}
}
}
}
以上的X就是我向线性基中插入的元素,DP代表我的线性基集合,例如原序列 1 2 3 线性基插入的就是 1 2 ,
1的二进制位01 2的二进制10 两个数异或 可以得到 3 11
求异或最大值
int max_xor()
{
int ans=0;
for(int i=61;i>=0;i--)
if(ans^dp[i]>ans)
ans=ans^dp[i];
return ans;
}
因为我们求得最大值,所以,我们从二进制高位开始枚举,因为异或后后面得低位会变,但是造成的影响小于最高位。
求异或最小值
int min_xor()
{
int cnt=0;
for(int i=0; i<=61; i++)
if(dp[i])
cnt++;
if(cnt<n)///cnt代表线性基的个数,n代表原序列个数
return 0;
else
{
for(int i=0; i<=61; i++)
if(dp[i])
return dp[i];
}
}
因为异或其他都会使结果变大,所以我们直接去线性基的最低位即可
求第K小
首先,如果我们要求第三小的异或值;现在线性基里第一小的01,第二小的10,第三小的就是11,是不是就是第一小与第二小的异或结果就可以表示第三异或小。
需要改造一下线性基,目的是让第x位为1的元素 (即a[x]) 在线性基中只有他的第x位为1(唯一性),比如 a[4] = ,那就让其他元素的第四位都为0,处理完后再把a数组的元素从小到大依次放进b数组,求第k小时,只要把k二进制拆分,第j位是1就异或 b[j-1],比如求第小,答案就是 b[0] ^ b[1],b数组相当于二进制位,,只不过这里是b[0] ^ b[1],再举个例子:b[0] = ,b[1] = ,b[2] = ,那么最小是b[0],其次是b[1],再其次是b[0]^b[1],接下来是b[2],b[2]^b[0],b[2]^b[1],最后是b[0]^b[1]^b[2],原理就和改造线性基有关,读者可以根据上文提到的唯一性结合二进制意会便可明白。(ps:同样要考虑n和m的关系)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=200;
int a[maxn];
int dp[maxn];///线性基
int dp1[maxn];///改造线性基
int cnt=0,n;///cnt代表线性基的元素个数,
void insert_num(int x)///初始线性基
{
for(int i=61; i>=0; i--)
{
if(x&1ll<<i)
{
if(dp[i])
x^=dp[i];///保证每个位置元素的唯一性
else
{
dp[i]=x;
break;
}
}
}
}
void exchange()///改造线性基
{
for(int i=0; i<=61; i++)
{
for(int j=i-1; j>=0; j--)
if(dp[i]&(1ll<<j))///其他位变成0,保证唯一性
dp[i]^=dp[j];
if(dp[i])
dp1[cnt++]=dp[i];
}
}
int min_k_num(int k)///求第K小
{
int ans=0;
for(int i=0; i<cnt; i++)
{
if((k>>i)&1)
ans^=dp1[i];
}
return ans;
}
int main()
{
int k;
scanf("%d %d",&n,&k);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
insert_num(a[i]);
}
exchange();
ull max_knum=1<<cnt;
if(cnt<n&&k==1)
cout<<"0"<<endl;
else
{
if(cnt<n)
k--;
if(max_knum<k)///线性基能产生的最大元素个数小于求的K小
cout<<"-1"<<endl;
else
cout<<min_k_num(k)<<endl;
}
return 0;
}