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;
}

浙公网安备 33010602011771号