JZOJ 5553 謎(線性基,矩陣的秩)

Description:

在這裏插入圖片描述
在這裏插入圖片描述

題解:

考慮如何在多項式複雜度內求完美匹配的方案數mod 2

完美匹配相當於求所有排列p的a[i][p[i]]\prod a[i][p[i]]

這個東西和行列式長得非常像啊:
A=p(1)pA[i][p[i]]|A|=\sum_{排列p}{(-1)}^{p的逆序對數}*\prod A[i][p[i]]

(1)(-1)在mod 2意義下就是1,所以 mod 2=A mod 2方案數~mod~2=|A|~mod~2

直接高斯消元可以獲得40分。

A=1(mod 2)|A|=1(mod~2)也就是A滿秩。

考慮把一行替換後依然滿秩的條件,首先替換前的秩必須=n或n-1,因爲替換一行秩最多+1。

替換前=n
那麼新的這一行一定能被前面的表示,顯然的是,那麼表示這一行的行中包含要替換的那一行。

替換前=n-1
首先新的這一行不能被表示,並且替換的那行是刪掉後秩不變的行,我們設這種行爲多餘的行。

考慮怎麼求多餘的行,在構建線性基的過程中,有一行不能被加進去,這一行肯定是,並且表示這一行的行也是。

那麼預處理是O(n3/Ω)O(n^3/Ω)的,查詢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));
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章