Description:
題解:
考慮如何在多項式複雜度內求完美匹配的方案數mod 2
完美匹配相當於求所有排列p的
這個東西和行列式長得非常像啊:
在mod 2意義下就是1,所以
直接高斯消元可以獲得40分。
也就是A滿秩。
考慮把一行替換後依然滿秩的條件,首先替換前的秩必須=n或n-1,因爲替換一行秩最多+1。
替換前=n
那麼新的這一行一定能被前面的表示,顯然的是,那麼表示這一行的行中包含要替換的那一行。
替換前=n-1
首先新的這一行不能被表示,並且替換的那行是刪掉後秩不變的行,我們設這種行爲多餘的行。
考慮怎麼求多餘的行,在構建線性基的過程中,有一行不能被加進去,這一行肯定是,並且表示這一行的行也是。
那麼預處理是的,查詢
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
#define gc getchar
int get() {
char c = ' ';
while(c != '0' && c != '1') c = gc();
return c - '0';
}
const int N = 1005;
int n, m, k;
typedef bitset<N> jz;
jz a[N];
struct nod {
jz z[N], a[N], b[N], c, d, f;
int zhi, fail;
jz e[N], w[N];
int ky[N];
void build(int t) {
fo(i, 1, n) {
int Z = zhi;
c.reset(); c[i] = 1;
fd(j, n, 1) if(z[i][j]) {
if(a[j].count()) {
z[i] ^= a[j];
c ^= b[j];
} else {
zhi ++;
a[j] = z[i]; b[j] = c;
fo(k, 1, j - 1) if(a[j][k] && a[k].count())
a[j] ^= a[k], b[j] ^= b[k];
fo(k, j + 1, n) if(a[k][j])
a[k] ^= a[j], b[k] ^= b[j];
break;
}
}
if(Z == zhi) d = c;
}
if(zhi == n - 1) f = d;
fo(i, 1, t) {
if(zhi == n) {
fo(j, 1, n) if(e[i][j]) w[i] ^= b[j];
} else
if(zhi == n - 1) {
fd(j, n, 1) if(e[i][j])
e[i] ^= a[j];
ky[i] = !e[i].count();
}
}
}
int query(int x, int y) {
if(zhi < n - 1) return 0;
if(zhi == n) return w[x][y];
if(zhi == n - 1) return !ky[x] && f[y];
}
} s1, s2;
int q, ty, x, y;
int main() {
freopen("maze.in", "r", stdin);
freopen("maze.out", "w", stdout);
scanf("%d", &n);
fo(i, 1, n) fo(j, 1, n) a[i][j] = get();
fo(i, 1, n) fo(j, 1, n) s1.z[i][j] = a[i][j], s2.z[j][i] = a[i][j];
scanf("%d %d", &m, &k);
fo(i, 1, m) fo(j, 1, n) s1.e[i][j] = get();
fo(i, 1, k) fo(j, 1, n) s2.e[i][j] = get();
s1.build(m); s2.build(k);
pp("%d\n", s1.zhi == n);
scanf("%d", &q);
fo(ii, 1, q) {
scanf("%d %d %d", &ty, &x, &y);
if(ty == 0) {
pp("%d\n", s1.query(y, x));
} else {
pp("%d\n", s2.query(y, x));
}
}
}