P10499 开关问题 Sol

题目链接

高斯消元为数不多的应用。

将问题转化成一系列的方程组,则是对于每一个 \(i\),有 \(\oplus_{j=1}^n B_{i,j} t_j = s_i \oplus t_i\),其中 \(B_{i,j}\) 表示操作 \(j\) 开关 \(i\) 会不会亮。

考虑使用高斯消元进行求解。则最终的结果里,每有一个方程组满足系数全为 0 结果为 0,则答案乘 2,如果有一个方程组系数全为 0 结果为 1,则无解。

可以利用 bitset 解决。时间复杂度 \(O(n^3/w)\)

Code

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
const int N = 35;
bitset<N> b[N];
int n;
int s[N],t[N];
void solve(){
	cin >> n;
	for(int i=1;i<=n;i++)
		b[i].reset();
	for(int i=1;i<=n;i++)
		cin >> s[i];
	for(int i=1;i<=n;i++){
		cin >> t[i];
		t[i] ^= s[i];
		b[i][i] = 1;
	}
	while(1){
		int x,y;
		cin >> x >> y;
		if(x == 0 && y == 0) break;
		b[y][x] = 1;
	}
	int rk = 1;
	for(int i=1;i<=n;i++){
		int id = rk;
		for(int j=rk;j<=n;j++)
			if(b[j][i]){
				id = j;
				break;
			}
		if(b[id][i] == 0) continue;
		swap(b[id],b[rk]);
		swap(t[id],t[rk]);
		for(int j=1;j<=n;j++){
			if(j == rk) continue;
			if(b[j][i]){
				b[j] ^= b[rk];
				t[j] ^= t[rk];
			}
		}
		rk ++ ;
	}
	int res = 1;
	if(rk <= n){
		for(int i=rk;i<=n;i++){
			res <<= 1;
			if(t[i]){
				cout << "Oh,it's impossible~!!\n";
				return ;
			}
		}
	}
	cout << res << "\n";
}
int main(){
	IOS;
	int T;
	cin >> T;
	while(T -- )
		solve();
	return 0;
}
posted @ 2026-05-22 21:51  WinterXorSnow  阅读(8)  评论(0)    收藏  举报