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;
} 
posted @ 2025-07-23 15:23  Astral_Plane  阅读(22)  评论(0)    收藏  举报