[JZOJ5553] 【NOI2019模擬6.24】謎【線性代數】

Description

有一個兩個部分均爲n個點的二分圖,給出它的鄰接矩陣,求這個二分圖的完美匹配數量模2的結果。

兩個部分另外各有m、k個備用點,給出它們與原圖中點的連邊關係。
現給出q組詢問,每次詢問形如將某一個部分的某個點u替換成該部分的某一個備用點v後,求這個二分圖的完美匹配數量。

詢問沒有後效性,也就是說每個詢問都是在原矩陣的基礎上做的。
n,m,k<=1000,q<=100000n,m,k<=1000,q<=100000

Solution

可以發現11(mod2)-1\equiv 1\pmod 2
因此完美匹配數模2等價於這個矩陣的行列式的奇偶性,也就是判斷矩陣是否滿秩。

顯然行和列可以分開來維護,因此我們只考慮行的情況。

求一個的很簡單,直接高斯消元+bitset優化,複雜度O(n3ω)O({n^3\over \omega})
詢問就是每次將矩陣的某一行替換成一個東西。

我們也可以將這個矩陣看做線性基,考慮它滿秩的條件。

顯然,替換一行至多使秩+1,因此我們只需要考慮原矩陣秩爲n或n-1的情況,否則全爲0

秩爲n,也就是說線性基的每一位都是滿的,n個向量線性無關,將某一行替換後仍然線性無關,也就是說替換上來的這個向量不能被剩餘n-1個的線性組合表示,這可以直接預處理m個向量被哪些的線性組合表示,複雜度是O(mn2ω)O({mn^2\over \omega})的。

秩爲n-1,那麼替換上來需要使秩+1,那麼就需要滿足被替換的向量能被剩餘n-1個向量的線性組合表示,且替換上的向量不能,這也可以直接預處理,複雜度是O(n3+mn2ω)O({n^3+mn^2\over \omega})

這樣預處理以後詢問就可以直接O(1)O(1)回答了。
時間複雜度O(n3+mn2ω)O({n^3+mn^2\over \omega})

題解給出了另外一種利用伴隨矩陣的方法,沒看懂…

Code

#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 1005
using namespace std;
bitset<N> a[N],b[N],c[N],d[N],b1[N],b2[N],bv1[N],bv2[N];
int n,m,l,q,id[N],id1[N],iw[N],iw1[N],cs,ip[N],ip1[N];
void make()
{
	int w=0;
	fo(i,0,n-1)
	{
		fo(k,w,n-1) if(a[k][i]) {swap(a[w],a[k]),swap(id[w],id[k]),swap(bv1[w],bv1[k]);break;}
		if(a[w][i])	
		{
			ip[w]=i;
			bv1[w][w]=1;
			fo(j,w+1,n-1) if(a[j][i]) a[j]^=a[w],bv1[j]^=bv1[w];
			w++;
		}
	}
	cs=w;
}
void make1()
{
	int w=0;
	fo(i,0,n-1)
	{
		fo(k,w,n-1) if(b[k][i]) {swap(b[w],b[k]),swap(id1[w],id1[k]),swap(bv2[w],bv2[k]);break;}
		if(b[w][i])	
		{
			ip1[w]=i;
			bv2[w][w]=1;
			fo(j,w+1,n-1) if(b[j][i]) b[j]^=b[i],bv2[j]^=bv2[w];
			w++;
		}
	}
}
int main()
{
	cin>>n;
	fo(i,0,n-1)
	{
		scanf("\n");
		fo(j,0,n-1) a[i][j]=b[j][i]=getchar()-'0';
		id[i]=id1[i]=i;
	}
	cin>>m>>l;
	fo(i,0,m-1)
	{
		scanf("\n");
		fo(j,0,n-1) c[i][j]=getchar()-'0';
	}
	fo(i,0,l-1) 
	{
		scanf("\n");
		fo(j,0,n-1) d[i][j]=getchar()-'0';
	}
	make();
	make1();
	int bp=(cs==n);
	cin>>q;
	printf("%d\n",bp);
	if(cs<n-1)
	{
		fo(j,1,q) printf("0\n");
		return 0;
	}	
	fo(i,0,n-1) iw[id[i]]=i,iw1[id1[i]]=i;
	fo(i,0,m-1)
		fo(j,0,n-1) if(c[i][ip[j]]&&a[j][ip[j]]) c[i]^=a[j],b1[i]^=bv1[j];
	fo(i,0,l-1) 
		fo(j,0,n-1) if(d[i][ip1[j]]&&b[j][ip1[j]]) d[i]^=b[j],b2[i]^=bv2[j];
	if(cs==n)
	{
		fo(i,1,q)
		{
			int tp,x,y;
			scanf("%d%d%d",&tp,&x,&y);
			x--,y--;
			if(tp==0) printf("%d\n",(int)b1[y][iw[x]]);
			else printf("%d\n",(int)b2[y][iw1[x]]);
		} 
	}
	else
	{
		bv1[n-1][n-1]=bv2[n-1][n-1]=1;
		fo(i,1,q)
		{
			int tp,x,y;
			scanf("%d%d%d",&tp,&x,&y);
			x--,y--;
			if(tp==0) printf("%d\n",(int)(c[y].any()&&bv1[n-1][iw[x]]));
			else printf("%d\n",(int)(d[y].any()&&bv2[n-1][iw1[x]]));
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章