Live2D

题解 开关问题

题目传送门

题目大意

给出 \(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;
}
posted @ 2020-09-06 12:48  Dark_Romance  阅读(152)  评论(0编辑  收藏  举报