zoukankan      html  css  js  c++  java
  • [CF736D] Permutations

    可以发现如果我们只询问一次答案其实就是询问将其二分图的邻接矩阵建出来的行列式 $(det A)$ 的奇偶性。

    因为 $det(A)=sum_{sigmain S_n} sgn(sigma)prod a_{i,sigma(i)}$ ,可以发现我们对于 $sigma$ 来说只有均为 $1$ 才做贡献,且由于奇偶性我们不需要知道 $sgn(sigma)$ 。

    故我们只需要快速求将一个 $1$ 改成 $0$ 的行列式值为多少。

    根据
    $$
    det(A)=sum_{c=1}^n a_{r,c}A_{r,c}
    $$
    其中 $A_{r,c}$ 表示 $a_{r,c}$ 的代数余子式,$A_{i,j}=(-1)^{i+j} M_{i,j}$ ,$M_{i,j}$ 表示 $A$ 中删去第 $i$ 行第 $j$ 列的行列式。

    则我们将 $a_{r,c}=1$ 改成 $a_{r,c}=0$ 时我们只需要知道 $A_{r,c}$ 的奇偶性即可。

    由于
    $$
    sum_{c=1}^n a_{i,c}A_{j,c}=det(A)cdot [i=j]
    $$
    将其按照矩阵乘法写出即为
    $$
    A(A_{i,j})^T=det(A)cdot I_n
    $$
    其中 $A^*=(A_{i,j})^T $,$A^*$ 表示 $A$ 的伴随矩阵。

    其实我们将行/列展开的值是一样的,故 $AA^*=A^*A=det(A)cdot I_n$ 。

    由于我们只需要快速知道 $A_{r,c}$ 即可,根据上式可写
    $$
    A^*=det(A)cdot A^{-1}
    $$
    又由于 $det(A)$ 为奇数,则我们只需要求 $A^{-1}$ 做个矩阵求逆就好啦!

    求逆由于为 $0/1$ 异或故利用 $bitset$ 优化,时间复杂度 $O(dfrac{n^3}{w})$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<climits>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<bitset>
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    using namespace std;
    inline int read(){
        int f=1,ans=0; char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=2e3+11;
    const int MAXM=5e5+11;
    bitset<MAXN*2> A[MAXN];
    int N,M,U[MAXM],V[MAXM];
    void print(){printf("==========
    ");for(int i=1;i<=N;i++){for(int j=1;j<=2*N;j++) cout<<A[i][j]<<" ";printf("
    ");}printf("===========
    ");}
    void Gauss(){
        for(int i=1;i<=N;i++){
            int ps=0; for(int j=i;j<=N;j++) if(A[j][i]){ps=j;break;}
            swap(A[i],A[ps]);
            for(int j=1;j<=N;j++){
                if(!A[j][i]||i==j) continue;
                A[j]^=A[i];
            }
        }return;
    }
    int main(){
        //freopen("2.in","r",stdin);
        N=read(),M=read(); for(int i=1;i<=M;i++){int u=read(),v=read();U[i]=u,V[i]=v;A[u][v]=1;}
        for(int i=1;i<=N;i++) A[i][i+N]=1; Gauss();
        for(int i=1;i<=M;i++) printf(A[V[i]][U[i]+N]?"NO
    ":"YES
    ");
        return 0;
    }
    View Code
  • 相关阅读:
    基于ARP的网络扫描工具netdiscover
    渗透测试集成环境Faraday
    NBNS扫描工具nbtscan-unixwiz
    分享Kali Linux 2017年第18周镜像文件
    Hat's Fibonacci
    N!
    A + B Problem II(大数加法)
    产生冠军(拓扑排序)
    确定比赛名次
    Legal or Not(模板题)
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/14282661.html
Copyright © 2011-2022 走看看