Description:
题解:
考虑如何在多项式复杂度内求完美匹配的方案数mod 2
完美匹配相当于求所有排列p的 ∏ a [ i ] [ p [ i ] ] \prod a[i][p[i]] ∏a[i][p[i]]
这个东西和行列式长得非常像啊:
∣
A
∣
=
∑
排
列
p
(
−
1
)
p
的
逆
序
对
数
∗
∏
A
[
i
]
[
p
[
i
]
]
|A|=\sum_{排列p}{(-1)}^{p的逆序对数}*\prod A[i][p[i]]
∣A∣=∑排列p(−1)p的逆序对数∗∏A[i][p[i]]
( − 1 ) (-1) (−1)在mod 2意义下就是1,所以 方 案 数 m o d 2 = ∣ A ∣ m o d 2 方案数~mod~2=|A|~mod~2 方案数 mod 2=∣A∣ mod 2
直接高斯消元可以获得40分。
∣ A ∣ = 1 ( m o d 2 ) |A|=1(mod~2) ∣A∣=1(mod 2)也就是A满秩。
考虑把一行替换后依然满秩的条件,首先替换前的秩必须=n或n-1,因为替换一行秩最多+1。
替换前=n
那么新的这一行一定能被前面的表示,显然的是,那么表示这一行的行中包含要替换的那一行。
替换前=n-1
首先新的这一行不能被表示,并且替换的那行是删掉后秩不变的行,我们设这种行为多余的行。
考虑怎么求多余的行,在构建线性基的过程中,有一行不能被加进去,这一行肯定是,并且表示这一行的行也是。
那么预处理是 O ( n 3 / Ω ) O(n^3/Ω) O(n3/Ω)的,查询 O ( 1 ) O(1) O(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));
}
}
}