線性基處理異或運算——模板+例題
阿新 • • 發佈:2019-01-10
線性基:處理異或操作的強大工具,思想也是可以借鑑的。
作用:用於處理多個數中選取一些數的XOR的最大值,最小值,第k大值,並可以查詢能否通過集合中任意個數XOR得到,時間複雜度為O(n*logn)
具體模板如下,思路和程式碼均參考於大佬的部落格,感謝解惑~
連結:傳送門
模板:
struct Linear_Basis
{
int num[max_log];//插入陣列
void init()
{
memset(num,0,sizeof(num));
}
//將u插入num陣列中
void insert(int u)
{
int i;
for(i=max_log;i>=0;i--)
{
if(u&(1<<i))//如果u的這一位有值,則進行判斷
{
if(!num[i])//如果這位為0
{
num[i]=u;//u賦值給它
}
else
{
u^=num[i];//不為0,則u異或這個數
}
}
}
}
/*
操作之後u只有兩種結果:
1.被記錄到了陣列中
2.未被記錄,則此時u必定為0,說明此時的線性基已經能通過Xor得到u.
因此我們可以用這種方法來判斷此時是否存在Xor值為u的子集.
*/
//查詢操作
bool check(int u)
{
int i;
for(i=max_log;i>=0;i--)
{
if(u&(1<<i))//如果u這一位有數
{
if(!num[i])//num[i]這一位為0
{
return 0;
}
else
u^=num[i];//否則u取異或num[i]
}
}
return 1;
}
//查詢最大值
int aks_max()
{
int res=0,i;
for(i=max_log;i>=0;i--)
{
if((res^num[i])>res)res^=num[i];
}
return res;
}
//查詢最小值
int ask_min()
{
int i;
for(i=0;i<=63;i++)
{
if(num[i]) return num[i];//最小的非0數就是最小值
}
}
//查詢第k小/大
/*
首先將陣列中的所有數變成包含這個最高位且可以通過Xor得到的最小值.
具體實現方法就是每一位向後掃,若Xor後變小,則Xor.
之後就可以發現第k大/小隻要將k改為二進位制後,將二進位制所對應的位置的數Xor起來即可.
*/
int ask_kth(int k)
{
int i,j,tmp[63],tt=-1,res=0;
for(i=0;i<=63;i++)
{
for(j=i-1;j>=0;j--)
{
if(num[i]&(1 << j)) num[i]^=num[j];
}
if(num[i]) tmp[++tt]=num[i];
}
for(i=0;i<=tt;i++)
{
if((1 << i)&k) res^=tmp[i];
}
return res;
}
};
小a有n個數,他提出了一個很有意思的問題:他想知道對於任意的x, y,能否將x與這n個數中的任意多個數異或任意多次後變為y
思路:注意到若x^一堆東西=y,則必有x^y=一堆東西,就轉化成查詢集合中任意數異或可不可以達到x^y這個數,也就是線性基模板題了~
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=1e5+10;
const int max_log=100;
int a[maxn];
struct Linear_Basis
{
int num[max_log];//插入陣列
void init()
{
memset(num,0,sizeof(num));
}
//將u插入num陣列中
void insert(int u)
{
int i;
for(i=max_log;i>=0;i--)
{
if(u&(1<<i))//如果u的這一位有值,則進行判斷
{
if(!num[i])//如果這位為0
{
num[i]=u;//u賦值給它
break;
}
else
{
u^=num[i];//不為0,則u異或這個數
}
}
}
}
/*
操作之後u只有兩種結果:
1.被記錄到了陣列中
2.未被記錄,則此時u必定為0,說明此時的線性基已經能通過Xor得到u.
因此我們可以用這種方法來判斷此時是否存在Xor值為u的子集.
*/
//查詢操作
bool check(int u)
{
int i;
for(i=max_log;i>=0;i--)
{
if(u&(1<<i))//如果u這一位有數
{
if(!num[i])//num[i]這一位為0
{
return 0;
}
else
u^=num[i];//否則u取異或num[i]
}
}
if(u==0)return 1;
else return 0;
}
};
Linear_Basis xxj;
int main()
{
int n,m;
scanf("%d",&n);
xxj.init();
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
xxj.insert(a[i]);
}
scanf("%d",&m);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
int temp=x^y;
if(xxj.check(temp))
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
return 0;
}