Description
有一個兩個部分均爲n個點的二分圖,給出它的鄰接矩陣,求這個二分圖的完美匹配數量模2的結果。
兩個部分另外各有m、k個備用點,給出它們與原圖中點的連邊關係。
現給出q組詢問,每次詢問形如將某一個部分的某個點u替換成該部分的某一個備用點v後,求這個二分圖的完美匹配數量。
詢問沒有後效性,也就是說每個詢問都是在原矩陣的基礎上做的。
Solution
可以發現
因此完美匹配數模2等價於這個矩陣的行列式的奇偶性,也就是判斷矩陣是否滿秩。
顯然行和列可以分開來維護,因此我們只考慮行的情況。
求一個的很簡單,直接高斯消元+bitset優化,複雜度
詢問就是每次將矩陣的某一行替換成一個東西。
我們也可以將這個矩陣看做線性基,考慮它滿秩的條件。
顯然,替換一行至多使秩+1,因此我們只需要考慮原矩陣秩爲n或n-1的情況,否則全爲0
秩爲n,也就是說線性基的每一位都是滿的,n個向量線性無關,將某一行替換後仍然線性無關,也就是說替換上來的這個向量不能被剩餘n-1個的線性組合表示,這可以直接預處理m個向量被哪些的線性組合表示,複雜度是的。
秩爲n-1,那麼替換上來需要使秩+1,那麼就需要滿足被替換的向量能被剩餘n-1個向量的線性組合表示,且替換上的向量不能,這也可以直接預處理,複雜度是。
這樣預處理以後詢問就可以直接回答了。
時間複雜度
題解給出了另外一種利用伴隨矩陣的方法,沒看懂…
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]]));
}
}
}