题解 开关问题
题目大意
给出 \(n\) 个开关,有很多对关系 \(x,y\) ,满足你改变 \(x\) 的状态 \(y\) 的状态也会改变。问从初始状态变为结束状态有多少种方案数(不考虑操作顺序)。
\(n\le 30\)
思路
算是高斯消元一种比较奇妙的应用吧。
我们首先发现顺序是不影响答案的,然后对于一个开关就只有改变或者不改变两种选择,我们假设这个为 \(x[i]\),我们可以得到关系式:
\[st[i]\otimes(a[i][1]\times x[1]\otimes a[i][2]\times x[2]\otimes ... \otimes a[i][n]\times x[n])=ed[i]
\]
其中 \(st[i],ed[i]\) 分别表示初始状态和结束状态,\(a[i][j]\) 表示 \(i\) 是否随 \(j\) 变化而变化。
然后你发现我们如果对这个东西进行高斯消元,答案就是 \(2\) 的自由元个数。
时间复杂度 \(\Theta(n^3)\) 。
\(\texttt{Code}\)
#define Int register int
#define MAXN 35
template <typename T> void read (T &x){x = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){x = x * 10 + c - '0';c = getchar();}x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) putchar ('-'),x = -x;if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int n,st[MAXN],ed[MAXN],mat[MAXN][MAXN];
int Gauss (){//输出自由元的个数
Int i = 1,col = 1;
for (;i <= n && col <= n;++ i,++ col){
int pos = i;
for (Int j = i + 1;j <= n;++ j) if (mat[j][col] > mat[pos][col]) pos = j;
if (i ^ pos) swap (mat[i],mat[pos]);
if (mat[i][col] == 0){
-- i;
continue;
}
for (Int j = i + 1;j <= n;++ j)
if (mat[j][col])
for (Int k = col;k <= n + 1;++ k) mat[j][k] ^= mat[i][k];
}
for (Int j = i;j <= n;++ j) if (mat[j][col]) return -1;
return n - i + 1;
}
signed main(){
int t;read (t);
while (t --){
read (n);
memset (mat,0,sizeof (mat));
for (Int i = 1;i <= n;++ i) read (st[i]),mat[i][i] = 1;
for (Int i = 1;i <= n;++ i) read (ed[i]),mat[i][n + 1] = ed[i] ^ st[i];
for (Int x,y;;){
read (x,y);
if (!x && !y) break;
else mat[y][x] = 1;
}
int get = Gauss ();
if (get == -1) puts ("Oh,it's impossible~!!");
else write (1 << get),putchar ('\n');
}
return 0;
}