CF736D Permutations
Link
我们可以把它转化成二分图匹配。
矩阵\(\mathbf A\)满足\(a_{i,j}=[\exists e(i,j)]\),那么总的方案就是\(\sum\limits_{p}\prod\limits_{i=1}^na_{i,p_i}\)。
显然\(1\equiv-1\pmod2\),因此总的方案就是\(\det(\mathbf A)\)。
考虑容斥,对于不选\((i,j)\)的方案,我们可以用总方案减去强制选的方案。
题目告诉我们\(\det(\mathbf A)\equiv1\pmod2\),那么我们只需要计算强制选的方案的奇偶性然后取个反就好了。
强制选\((i,j)\)的方案其实就是\(M_{i,j}\)也就是\(C_{i,j}\)。
我们知道\(\mathbf A^{-1}=\frac{\mathbf A^*}{\det(\mathbf A)}\),因为\(\det(\mathbf A)\equiv1\pmod2\),所以\(\mathbf A^{-1}\)存在并且\(\mathbf A^*=\mathbf A^{-1}\)。
那么我们Gauss消元求出\(\mathbf A^{-1}\)就能求出\(\mathbf A^*\)了,而根据定义我们知道\(C_{i,j}=\mathbf A^*_{j,i}\)。
注意到这是一个\(01\)矩阵,因此我们可以用bitset优化。
#include<cstdio>
#include<bitset>
#include<utility>
#define pi pair<int,int>
#define fi first
#define se second
using std::pair;
using std::bitset;
using std::swap;
int read(){int x;scanf("%d",&x);return x;}
bitset<4007>a[2007];pi e[500007];
int main()
{
int n=read(),m=read();
for(int i=1,u,v;i<=m;++i) e[i]={u=read(),v=read()},a[u][v]=1;
for(int i=1;i<=n;++i) a[i][i+n]=1;
for(int i=1;i<=n;++i)
{
if(!a[i][i]) for(int j=i+1;j<=n;++j) if(a[j][i]) {swap(a[j],a[i]);break;}
for(int j=1;j<=n;++j) if(j^i&&a[j][i]) a[j]^=a[i];
}
for(int i=1;i<=m;++i) puts(a[e[i].se][e[i].fi+n]? "NO":"YES");
}