行列式求法和矩阵树定理

1.矩阵树定理
无向图,有n个点,如果说i-j之间有连边,那么矩阵g[i][j]=g[j][i]=-1(i-j之间的边的数量),否则值为0
矩阵上对角线上的值为该点的度数,g[i][i]=d[i];
生成树个数:任选i,去掉i行i列之后的行列式的值
生成树的权值=边权的乘积,所有生成树的权值之和?
i-j之间右边,g[i][j]=-w[i][j]之和
g[i][i]=所有w[i][j]之和

时间复杂度:n^3
logW

int g[N][N];

int calc(int n){
	int ans=1;
	for(int i=1;i<=n;i++) 
		for(int j=1;j<=n;j++) g[i][j]%=mod;
	
	for(int i=1;i<=n;i++)
	 for(int j=i+1;j<=n;j++){
	 	int x=i,y=j;
	 	while(g[x][i]){
	 		int t=g[y][i]/g[x][i];
	 		for(int k=i;k<=n;k++){
	 			g[y][k]=(g[y][k]-t*g[x][k])%mod;
			 }
			swap(x,y);
		 }
		 if(x==i){
		 	for(int k=i;k<=n;k++) swap(g[i][k],g[j][k]);
		 	ans=-ans;
		 }
		 if(g[i][i]==0){
		 	return 0;
		 }
		 ans=ans*g[i][i]%mod;
	 }
	 if(ans<0)ans+=mod;
	 return ans;
	 
}

void slove(){
	int n,m;cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;cin>>u>>v;
		g[u][v]--,g[v][u]--;
		g[u][u]++,g[v][v]++;
	}
	cout<<calc(n-1)<<endl;//删掉第n行,第n列 
} 

2.线性基
给一个数组a有n个元素,求其所有子集的异或和(2^n个子集),或者求有多少个不同的异或和
a1,a2,a3,a4,a5,……an
如果把ai替换成ai^aj,那么这个数组的异或生成空间不变,所以可以类似于行列式
基础模板:

const int B=60;
struct linear_basis{
	int num[B+1];
	bool insert(int x){
		for(int i=B;i>=0;i--){
			if(x>>i&1){
				if(num[i]==0){num[i]=x;return true;}
				x^=num[i];
			}
		}
		return false;
	}
	int querymin(int x){
		 for(int i=B;i>=0;i--){
		 	x=min(x,x^num[i]);
		 }
		 return x;  
	}
	int querymax(int x){
		 for(int i=B;i>=0;i--){
		 	x=max(x,x^num[i]);
		 }
		 return x;  
	}
};

线性基求第k大

const int B=60;
struct linear_basis{
	int num[B+1];
	bool insert(int x){
		for(int i=B;i>=0;i--){
			if(x>>i&1){
				if(num[i]==0){num[i]=x;return true;}
				x^=num[i];
			}
		}
		return false;
	}
	int querymin(int x){
		 for(int i=B;i>=0;i--){
		 	x=min(x,x^num[i]);
		 }
		 return x;  
	}
	int querymax(int x){
		 for(int i=B;i>=0;i--){
		 	x=max(x,x^num[i]);
		 }
		 return x;  
	}
}T;

void slove(){
	int n,k;cin>>n>>k;
	int zero=0;
	for(int i=1;i<=n;i++){
		int x;cin>>x;
		if(!T.insert(x))zero++;
	}
	/*
	总共有2^n个数,但是在线性基内最多只有2^B个数 
	如果说有一个数没有被插入进去的话,那么就说明这个数的出现与否都无关紧要,
	所以他可以让线性基内能表现出来的数的出现次数乘2 
	*/
	k>>=zero; 
	vector<int> num;
	for(int i=0;i<=B;i++)if(T.num[i]!=0){
		num.push_back(T.num[i]);
	}
	int m=num.size();
	int x=0;
	for(int i=m-1;i>=0;i--)
	if(k>>i&1){//如果说k这位是1的话,那么肯定是要取最大的 
		x=max(x,x^num[i]);
	}else x=min(x,x^num[i]);//否则就取最小的 
	cout<<x<<endl;
} 

最大XOR和路径

posted @ 2024-10-03 15:43  MENDAXZ  阅读(4)  评论(0编辑  收藏  举报