码迷,mamicode.com
首页 > 其他好文 > 详细

行列式

时间:2019-11-29 13:15:14      阅读:92      评论:0      收藏:0      [点我收藏+]

标签:begin   debug   tor   lse   sizeof   lin   ack   意义   err   

行列式

题目大意

? 给定一个无向联通图,求其邻接矩阵行列式。

? \(n\leq 3\times 10^4 , m\leq 3\times 10^5\) ,保证每个边双联通分量点数 \(\leq 50\)

题解

? 考虑这个邻接矩阵的行列式的意义,在不考虑行列式中的 \(-1\) 系数的情况下,就是选出若干个存在的有向环,不重不漏地覆盖每个点的方案数。

? 我们发现一个排列中环与环之间产生的逆序对数是可以忽略的,因此如果每个环都在一个边双内部,答案就是每个边双的答案的乘积。

? 考虑一个桥出现在了环中,那么一定是桥的两个端点组成了二元环。

? 考虑建出边双树, \(F_{x,0/1}\) 表示 \(x\) 号边双,其与边双树父亲连接的那个点有没有被环覆盖的方案数。
? 若 \(x\) 中一个点 \(u\)\(x\) 的某个儿子 \(y\) 中的一个点 \(v\) 组成了二元环,那么我们可视为在 \(x\) 内部的邻接矩阵中,\(u\) 自己添加了一个自环,其权值自带 \(-1\) 的系数,然后求行列式即可算出 \(F_{x,1}\)

同样,我们将 \(x\)\(x\) 父亲连接的点 \(w\) 在邻接矩阵的边都扣抠掉,并加上一个自环即可等价算出 \(F_{x,0}\)

#include<bits/stdc++.h>
#define debug(x) cerr<<#x<<" = "<<x
#define sp <<"  "
#define el <<endl
#define fgx cerr<<"-----------------------------------"<<endl
#define LL long long
#define uint unsigned int
#define ULL unsigned long long
#define LDB long double 
#define DB double
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
using namespace std;
inline int read(){
    int nm=0; bool fh=true; char cw=getchar();
    for(;!isdigit(cw);cw=getchar()) fh^=(cw=='-');
    for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
    return fh?nm:-nm;
}
#define mod 998244353
namespace CALC{
    inline int add(int x,int y){return (x+y>=mod)?(x+y-mod):(x+y);}
    inline int mns(int x,int y){return (x-y<0)?(x-y+mod):(x-y);}
    inline int mul(int x,int y){return (LL)x*(LL)y%mod;}
    inline void upd(int &x,int y){x=((x+y>=mod)?(x+y-mod):(x+y));}
    inline void dec(int &x,int y){x=((x-y<0)?(x-y+mod):(x-y));}
    inline int qpow(int x,int sq){int res=1;for(;sq;sq>>=1,x=mul(x,x))if(sq&1)res=mul(res,x);return res;}
}using namespace CALC;
#define M 30020
int n,m,t[53][53],p[53][53];
inline int calc(int K,int ans=1){
    if(!K) return 1; memcpy(p,t,sizeof(p));
    for(int k=1,i=1;i<=K;i++){
        for(k=i;k<=K&&!p[k][i];++k); if(k>K) return 0;
        if(k^i){for(int j=i;j<=K;j++) swap(p[k][j],p[i][j]);ans=mul(ans,mod-1);}
        int bas=p[i][i]; ans=mul(ans,bas),bas=qpow(bas,mod-2);
        for(int j=i;j<=K;j++) p[i][j]=mul(p[i][j],bas);
        for(int w=i+1;w<=K;w++) if(p[w][i]){
            int tmp=p[w][i];
            for(int j=i;j<=K;j++) dec(p[w][j],mul(tmp,p[i][j]));
        }
    } return ans;
}
int fs[M],nt[M*20],to[M*20],u[M*10],v[M*10],tmp,id[M];
inline void link(int x,int y){nt[tmp]=fs[x],fs[x]=tmp,to[tmp++]=y;}
int dfn[M],low[M],cnt,be[M],F[M][2],anc[M],tot,G[M],S[M],top;
vector<int>nd[M],eg[M],son[M];
inline void init(int x,int last){
    dfn[x]=++cnt,low[x]=cnt,S[++top]=x;
    for(int i=fs[x];i!=-1;i=nt[i]) if(to[i]^last){
        if(!dfn[to[i]]) init(to[i],x);
        low[x]=min(low[x],low[to[i]]);
    } if(low[x]<dfn[x]) return; ++tot;
    while(!be[x]) be[S[top]]=tot,nd[tot].pb(S[top]),top--;
    if(last) son[last].pb(x); anc[tot]=x;
}
inline void DP(int w){
    for(int i=0,TP=nd[w].size();i<TP;i++)
        for(int x=nd[w][i],j=0,SZ=son[x].size();j<SZ;++j) DP(be[son[x][j]]);
    int K=nd[w].size(); memset(t,0,sizeof(t)); sort(nd[w].begin(),nd[w].end());
    for(int j=0;j<K;j++){
        int y,x=nd[w][j],g1=0,g0=1; id[x]=j+1;
        for(int i=0,TP=son[x].size();i<TP;++i){
            y=be[son[x][i]],g1=mul(g1,F[y][1]);
            dec(g1,mul(g0,F[y][0])),g0=mul(g0,F[y][1]);
        } t[j+1][j+1]=g1,G[j+1]=g0;
    }
    for(int i=0,TP=eg[w].size();i<TP;i++){  
        int x=id[eg[w][i]/M],y=id[eg[w][i]%M];
        t[x][y]=G[x],t[y][x]=G[y];
    } F[w][1]=calc(K); int ps=id[anc[w]];
    for(int i=1;i<=K;i++) t[i][ps]=t[ps][i]=0;
    for(int i=1;i<K;i++) for(int j=1;j<K;j++){
        if(i<ps&&j<ps) continue;
        if(i<ps) t[i][j]=t[i][j+1];
        else if(j<ps) t[i][j]=t[i+1][j];
        else t[i][j]=t[i+1][j+1];
    } F[w][0]=calc(K-1);
    for(int x=anc[w],i=0,TP=son[x].size();i<TP;++i)
        F[w][0]=mul(F[w][0],F[be[son[x][i]]][1]);
}
int main(){
    n=read(),m=read(),read(),memset(fs,-1,sizeof(fs));
    for(int i=1,x,y;i<=m;i++) x=read(),y=read(),u[i]=x,v[i]=y,link(x,y),link(y,x); init(1,0);
    for(int i=1;i<=m;i++) if(be[u[i]]==be[v[i]]) eg[be[u[i]]].pb(u[i]*M+v[i]); DP(tot);
    printf("%d\n",F[tot][1]); return 0;
}

行列式

标签:begin   debug   tor   lse   sizeof   lin   ack   意义   err   

原文地址:https://www.cnblogs.com/OYJason/p/11956859.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!