N ≤ 28 個開關,初始狀態與目標狀態給定。操作開關 i 會翻轉自身及關聯開關 j 的狀態。每個開關最多操作一次。求達到目標狀態的方案數。
初始[k] ⊕ (Σ x_i * A[i][k]) = 目標[k],其中 A[i][k]=1 若操作 i 影響 k。A * x = b (mod 2),b[k] = 初始[k] ⊕ 目標[k]。標準高斯消元,把減法換為異或(^)。步驟:
0 = 1 行 → 無解。2^f。#includeusing namespace std; const int MAXN = 30; int mat[MAXN][MAXN], rhs[MAXN]; // 增廣矩陣 int gauss(int n) { int row = 0, col = 0, freeVar = 0; while (row < n && col < n) { int sel = row; while (sel < n && !mat[sel][col]) ++sel; if (sel == n) { ++freeVar; ++col; continue; } if (sel != row) { for (int j = col; j < n; ++j) swap(mat[row][j], mat[sel][j]); swap(rhs[row], rhs[sel]); } for (int i = row + 1; i < n; ++i) { if (mat[i][col]) { for (int j = col; j < n; ++j) mat[i][j] ^= mat[row][j]; rhs[i] ^= rhs[row]; } } ++row; ++col; } // 檢查無解 for (int i = row; i < n; ++i) if (rhs[i]) return -1; return freeVar; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; while (T--) { int n; cin >> n; memset(mat, 0, sizeof(mat)); for (int i = 0; i < n; ++i) { cin >> rhs[i]; mat[i][i] = 1; } for (int i = 0; i < n; ++i) { int t; cin >> t; rhs[i] ^= t; } int u, v; while (cin >> u >> v, u || v) { // 注意:題目給的是 "操作 i 影響 j",矩陣行是方程(受影響者),列是變量(操作者) // 方程 j: x_j ⊕ Σ x_i = b_j → mat[j][i] = 1 mat[v-1][u-1] = 1; } int f = gauss(n); if (f == -1) cout << "Oh,it's impossible~!!\n"; else cout << (1 << f) << '\n'; } return 0; }
i j 表示操作 i 影響 j,故 mat[j-1][i-1] = 1。mat[i][i]=1:操作自身翻轉自身。1 << f 計算方案數,f ≤ 28 可用 int 或 long long。POJ 1830 是「GF(2) 線性方程組高斯消元」的標準題。核心模板:增廣矩陣構建 → 異或消元 → 自由變量計數 → 2^f。同模板解決 HDU 1222、Codeforces 異或方程組計數問題。