【学习笔记】LGV引理
在有向无环图中,有一组起点 \(A=\{a_1,a_2,\cdots,a_n\}\) 与终点 \(B=\{b_1,b_2,\cdots,b_n\}\)。
定义 \(\omega(P)\) 为一条路径 \(P\) 中每条边权的乘积,即 \(\omega(P)=\prod_{e\isin P} w_e\)(可以看作是一条固定点路径中计算重边的边路径数)。
定义 \(e(a,b)\) 为两点之间所有路径的 \(\omega\) 之和,即 \(e(a,b)=\sum_{P:a\rightarrow b} \omega(P)\)。
设一个从 \(A\) 到 \(B\) 的路径组为 \(P=(P_1,P_2,\cdots,P_n)\),\(P_i=(a_i,b_{\sigma(i)})\),其中 \(\sigma\) 为任意一个 \(1\) 到 \(n\) 的排列。
则定义 \(\omega(P)=\prod_{i=1}^n \omega(P_i)\) 为该路径组的实际路径方案数。
定义 \(t(P)\) 为这个路径组涉及的排列 \(\sigma\) 的逆序对数。
那么LGV引理描述为,设一个矩阵
则有定理
其中 \(P\) 是一个从 \(A\) 到 \(B\) 的不相交路径组。
该定理的实际意义为,\(\det(M)\) 的值是所有不相交路径组方案数的带符号数量和。
证明:
由行列式定义知
观察 \(\prod_{i=1}^n\sum_{P:a_i\rightarrow b_{\sigma(i)}}\omega(P)\),实际上是所有从 \(A\) 到 \(B\) 排列为 \(\sigma\) 的路径组 \(P\) 的 \(\omega(P)\) 之和。
还没证明完,实际上这里的 \(P\) 为任意一个路径组,而引理描述的是不相交路径组。
设 \(U\) 为不相交路径组,\(V\) 为相交路径组,
我们要证的就是
实际上,我们在一组相交路径 \(P\) 中取一个相交路径中最小的二元组 \((i,j)\),
有路径 \(P_i:a_1\rightarrow u \rightarrow b_1\),\(P_j:a_2\rightarrow u \rightarrow b_2\)。
我们魔改一下路径使得 \(P_i:a_1\rightarrow u \rightarrow b_2\),\(P_j:a_2\rightarrow u \rightarrow b_1\)。通过这种构造得到了另一个相交路径组 \(P'\),容易发现
而对于任意的相交路径组,都可以通过这种交换得到一一对应的相交路径组,因此和为 \(0\)。
因此
证毕。
P6657【模板】LGV引理
由于 \(A\) 和 \(B\) 的坐标都是递增的,而要求起点终点一一对应,因此只有排列为顺排才可能不相交。
因此答案即为 \(\det(M)\)。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define ll long long
const ll mod=998244353;
const int maxn=105;
int t;
int a[maxn],b[maxn];
ll fac[1000005];
ll f[maxn][maxn];
ll qpow(ll a,ll b){
    ll ret=1;
    while(b){
        if(b&1) ret=ret*a%mod;
        a=a*a%mod;b>>=1;
    }
    return ret;
}
ll C(ll n,ll m){
    return fac[n]*qpow(fac[n-m],mod-2)%mod*qpow(fac[m],mod-2)%mod;
}
ll Guass(ll f[][maxn],int n){
    ll ret=1;
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            while(f[i][i]){
                ll div=f[j][i]/f[i][i];
                for(int k=i;k<=n;k++){
                    f[j][k]=(f[j][k]-div*f[i][k]%mod+mod)%mod;
                }
                swap(f[i],f[j]);
                ret=-ret;
            }
            swap(f[i],f[j]);ret=-ret;
        }
    }
    if(ret<0) ret+=mod;
    for(int i=1;i<=n;i++) ret=ret*f[i][i]%mod;
    return ret;
}
int main(){
#ifdef LOCAL
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    fac[0]=1;
    for(int i=1;i<1000005;i++) fac[i]=fac[i-1]*i%mod;
    scanf("%d",&t);
    while(t--){
        int n,m;
        memset(f,0,sizeof f);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&a[i],&b[i]);
        }
        for(int i=1;i<=m;i++){
            for(int j=1;j<=m;j++){
                if(b[j]<a[i]) continue;
                f[i][j]=C(n-1+b[j]-a[i],n-1);
            }
        }
        printf("%lld\n",Guass(f,m));
    }
    return 0;
}

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号