XOR線性代數
線性代數中,高斯消元,線性基等概念大家都不陌生。
我們考慮一般意義上線性代數的外延,簡單來講,其中的線性運算——加法不僅是加法,而今天要說的就是其(二進制下)不進位版本:異或。
我們發現,異或的線性代數算法不僅沒有變復雜,反而變簡單。
比如異或高斯消元,可以求線性基。
void Gauss_Elimination(int n)
{
int row = 1;
for (int col=BIT-1;~col&&row<=n;--col){
for (int i=row;i<=n;++i)
if(a[i][col]){
swap(a[row],a[i]);
break;
}
if(!a[row][col]) continue;
for(int i=1;i<=n;++i){
if(i==row) continue;
if(a[i][col]) a[i]^=a[row];
}
++row;
}
}
但是這種方式常數大,且不是一個一個insert進去的,在某些情境下不好用。
這時就用貪心去構造。
vector<int> insert(vector<int> p,int x){
for(int i=BIT-1;i>=0;i--){
if(!(x>>i&1)) continue;
if(!p[i]){
p[i]=x;
break;
}
x^=p[i];
}
return p;
}
(一組基p扔進去一個x返回一組新基)
這種方法可以做前幾天杭電round2的L題。
一個比較復雜的題是昆明2024區域賽金牌題E.Extracting Weights
我們先用所有符合條件的路徑求一組基(沒有則無解),然后再同樣跑一遍,但第一次跑系數矩陣,第二次跑增廣矩陣(多帶一個向量,把答案算出來)。
這里用的高斯消元是我發的板子改的,和上面說的又不完全一樣。
#include<bits/stdc++.h>
using namespace std;
int n,m;// 增廣矩陣n行m列
int k;
const int maxn=255;
const int NO_SOLUTION=-1;
const int UNLIMITED_SOLUTIONS=0;
const int SOLVED=1;
struct row{
bitset<maxn> a;
int res;
row operator -(const row& other)const{
row b;
b.a=a^other.a;
b.res=res^other.res;
return b;
}
bool iszero(){
return a.none();
}
}r[maxn*maxn];
struct row_bit{
bitset<maxn> a;
int from,to;
row_bit operator -(const row_bit& other)const{
row_bit b;
b.from=from;
b.to=to;
b.a=a^other.a;
return b;
}
bool iszero(){
return a.none();
}
}rb[maxn*maxn];
int fl=0;
vector<int> G[maxn];
vector<int> backup[maxn][maxn];
int fa[maxn],vis[maxn];
void dfs(int x,int to)
{
if(x==to)
{
fl=1;
return;
}
vis[x]=1;
for(int i=0;i<G[x].size();i++)
{
int v=G[x][i];
if(vis[v]) continue;
dfs(v,to);
if(fl==1)
{
fa[v]=x;
return;
}
}
}
int Gauss_Elimination_bit()
{
for(int i=1;i<=n;i++){
for(int j=i;j<=n*n;j++)
if(rb[j].a[i])
{
swap(rb[i],rb[j]);
break;
}
if(rb[i].iszero()){
for(int j=i;j<=n;j++)
if(rb[j].a[m]!=0) return NO_SOLUTION;
return UNLIMITED_SOLUTIONS;
}
int fir=0;
for(int j=1;j<=m;j++)
if(rb[i].a[j]) {fir=j;break;}
for(int j=1;j<=n*n;j++) if(j!=i&&rb[i].a[fir]==rb[j].a[fir]) rb[j]=rb[j]-rb[i];
}
return SOLVED;
}
int Gauss_Elimination()
{
for(int i=1;i<m;i++){
for(int j=i;j<=n;j++)
if(r[j].a[i])
{
swap(r[i],r[j]);
break;
}
int fir=0;
for(int j=1;j<=m;j++)
if(r[i].a[j]) {fir=j;break;}
for(int j=1;j<=n;j++) if(j!=i&&r[i].a[fir]==r[j].a[fir]) r[j]=r[j]-r[i];
}
return SOLVED;
}
int main()
{
scanf("%d%d",&n,&k);
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
int cnt=1;
rb[1].a.reset();rb[1].a.flip(1);rb[1].from=rb[1].to=1;
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
{
fl=0;
for(int t=1;t<=n;t++) fa[t]=vis[t]=0;
dfs(i,j);
vector<int> pa;
int now=j;
while(now!=i)
{
pa.push_back(now);
now=fa[now];
}
pa.push_back(i);
if(pa.size()!=k+1) continue;
cnt++;rb[cnt].a.reset();
for(int t=0;t<pa.size();t++)
{
rb[cnt].a.flip(pa[t]);
rb[cnt].from=i;
rb[cnt].to=j;
}
backup[i][j]=pa;
}
m=n;
if(Gauss_Elimination_bit()!=1)
{
printf("NO\n");
return 0;
}
printf("YES\n");
vector<pair<int,int> > query;
m=n+1;
for(int i=1;i<=n;i++)
{
int u=rb[i].from,v=rb[i].to;
if(u==1&&v==1) {r[i].a[1]=1;continue;}
query.push_back(make_pair(u,v));
for(int j=0;j<backup[u][v].size();j++)
{
r[i].a[backup[u][v][j]]=1;
}
}
printf("? %d ",query.size());
for(int i=0;i<query.size();i++)
{
printf("%d %d ",query[i].first,query[i].second);
}
fflush(stdout);
for(int i=1;i<=n;i++)
{
if(rb[i].from==1&&rb[i].to==1) continue;
scanf("%d",&r[i].res);
}
int ans=Gauss_Elimination();
printf("! ");
for(int i=1;i<=n;i++)
{
if(rb[i].from==1&&rb[i].to==1) continue;
printf("%d ",r[i].res);
}
fflush(stdout);
return 0;
}

浙公網安備 33010602011771號