Lindström–Gessel–Viennot lemma定理 行列式板子

https://blog.csdn.net/qq_37025443/article/details/86537261 博客

下面是wiki上的讲解,建议耐心地看一遍...虽然看了可能还是不懂

https://en.wikipedia.org/wiki/Lindström–Gessel–Viennot_lemma

Lindström–Gessel–Viennot lemma定理是

起点集合A=(a1,a2,a3..an),终点集合B=(b1.b2,b3,..bn)

假定P是从一条从一个点到另一个点的路径,定义w(P)=路径上经过的边的权值积

定义一个n元组P‘=(P1,P2,P3...PN)

Pi: -> 的路径

是{1,2,3,...n}的一种排列(类似于置换群的概念)

M行列式所求的值代表...(那句话我也不知道怎么翻译直接看原文吧)

下面这句话就是讲我们真正的用处——当所有边的权值都为1,并且 只有一种排列组合是可以的(即ai->bi)

那么M计算出来的值就是ai->bi不相交路径的方案数。此时e(a,b)就是a->b的合法路径的方案数

看了上面你可能还是不懂,其实在实际题目中用一下,你就可以知道他的套路了

Intersection is not allowed!
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 602    Accepted Submission(s): 195

Problem Description

There are K pieces on the chessboard.

The size of the chessboard is N*N.

The pieces are initially placed on the top cells of the board.

A piece located on (r, c) can be moved by one cell right to (r, c + 1) or one cell down to (r+1, c).

Your task is to count how many different ways to move all pieces to the given positions at the bottom of the board.

Furthermore, the paths of the pieces mustn’t intersect each other.

Input

The first line of input contains an integer T-the number of test cases.

Each test case begins with a line containing two integers-N(1<=N<=100000) and K(1<=K<=100) representing the size of the chessboard and the number of pieces respectively.

The second line contains K integers: 1<=a1<a2< …<aK<=N representing the initial positions of the pieces. That is, the pieces are located at (1, a1), (1, a2), …, (1, aK).

Next line contains K integers: 1<=b1<b2<…<bK<=N representing the final positions of the pieces. This means the pieces should be moved to (N, b1), (N, b2), …, (N, bK).

Output

Print consecutive T lines, each of which represents the number of different ways modulo 1000000007.

Sample Input

1

5 2

1 2

3 4

Sample Output

50

题意:

给你一个n*n的矩阵,再第一行一次有k个起点1<=a1<a2<a3<...<ak<=n

最后一行有n个终点1<=b1<b2<b3<...<bk<=n

你只能向右或向下走,问你有多少种路线方案,使得ai->bi  i=1...n

答案mod 1e9+7

解析:

e(a,b)是合法路径的方案数,那么我们就先将这个行列式填好

然后我们只需要用高斯消元法求出这个行列式的值就可以得出答案了。

也就是把通过行列式行变换把行列式转换成上(下)三角矩阵,然后将对角线上的元素乘起来就是答案了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long int ll;

const int MAXN = 2e5+10;
ll jc[MAXN];
ll inv[MAXN];

const ll MOD = 1e9+7;
const int N = 1e2+10;
ll a[N][N];

ll pow(ll a, ll n, ll p)    //快速幂 a^n % p
{
    ll ans = 1;
    while(n){
        if(n & 1) ans = ans * a % p;
        a = a * a % p;
        n >>= 1;
    }
    return ans;
}

ll niYuan(ll a, ll b)   //费马小定理求逆元
{
    return pow(a, b - 2, MOD);
}

inline ll C(int a, int b)    //计算C(a, b),a下,b上
{
    if(b>a) return 0;
    return jc[a] * inv[b] % MOD
        * inv[a-b]%MOD;
}

void init()
{
    ll p=1;
    jc[0]=1;
    jc[1]=1;
    inv[0]=1;
    inv[1]=1;
    for(int i=2;i<MAXN;i++){
        p=(p*i)%MOD;
        jc[i]=p;
        //inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
    }

    for(int i=2;i<MAXN;i++) inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;   //O(n)求逆元
    for(int i=2;i<MAXN;i++) inv[i]=inv[i-1]*inv[i]%MOD;   //扩展到i!的逆元
}

ll determinant(int n)
{
    //a为方阵
    //MOD根据实际情况而定
    ll ans=1;
    for(int k=1;k<=n;k++)  //将a[k+1..n][k]都变成0
    {
        ll pos=-1;
        for(int i=k;i<=n;i++)  //找到a[k..n][k]中第一个非0元素
            if(a[i][k])
            {
                pos=i;
                break;
            }
        if(pos==-1)return 0;  //没有的话行列式值为0
        if(pos!=k)  //将找到的那一行换到第k行,swap(a[k],a[pos])
            for(int j=k;j<=n;j++)swap(a[pos][j],a[k][j]);
        ll inv=niYuan(a[k][k],MOD);
        for(int i=k+1;i<=n;i++)
            if(a[i][k])
            {
                ans=ans*inv%MOD;   //下面的计算中第i行提高a[k][k]倍,所以答案需要除以a[k][k]才是正解
                for(int j=k+1;j<=n;j++)
                    a[i][j]=((a[i][j]*a[k][k]%MOD-a[k][j]*a[i][k]%MOD)%MOD+MOD)%MOD;
                a[i][k]=0;
            }
    }
    for(int i=1;i<=n;i++)
        ans=ans*a[i][i]%MOD;
    return ans;
}

int A[N],B[N];

int main()
{
    int t;
    init();
    scanf("%d",&t);
    while (t--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=k;i++) scanf("%d",&A[i]);
        for(int i=1;i<=k;i++) scanf("%d",&B[i]);

        for(int i=1;i<=k;i++)
        {
            for(int j=1;j<=k;j++)
            {
                a[i][j]=C(n+B[j]-(1+A[i]),n-1);
            }
        }
        printf("%lld\n",determinant(k));
    }
}

https://blog.csdn.net/qq_36368339/article/details/81133921

题意:给你一个矩阵(#表示不可走),两只乌龟从左上角出发到达右下角,中间不能相遇,存在多少种不同的方案,也就是两条不相交的路径的方案数.
分析:
LGV:(https://en.wikipedia.org/wiki/Lindstr%C3%B6m%E2%80%93Gessel%E2%80%93Viennot_lemma)
ps:我自己也不是很懂原理,但是知道怎么用,就说一下吧.
给定n个起点,n个终点(一个终点对应一个起点),LGV主要解决n∗nn∗n条路径不相交的方案数.
LGV是一个n阶的行列式,行代表起点,列代表终点,(i, j)表示第i个起点到第j个终点的方案数,最后行列式的值就是n条不相交路径的方案数.

有了LGV,这个题最大的麻烦解决了。两只乌龟同起点同终点,要分离出来,也就等价一只乌龟从(1, 2)出发,到(n - 1, m),另一只从(2, 1)到(n, m - 1),因为路径不相交,不懂得可以仔细想想。
有了起点,有了终点,每个起点对应每个终点的方案数,用DP转移一下行了,然后就套LGV问题解决.
相当于两个起点,两个终点的题,且起点的横坐标都是1,终点的横坐标都是n。

#include <stdio.h>
#include <cstring>
typedef unsigned long long LL;

const int MAXN = 3e3 + 5;
const int mod = 1e9 + 7;
LL dp[MAXN][MAXN];
char ma[MAXN][MAXN];

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; ++i) {
        getchar();
        for(int j = 1; j <= m; ++j) {
            ma[i][j] = getchar();
        }
    }
    if(ma[1][2] == ‘#‘ || ma[2][1] == ‘#‘) {
        puts("0");
        return 0;
    }
    if(ma[1][2] != ‘#‘) dp[1][2]++;
    for(int i = 1; i <= n; ++i) {
        for(int j = 2; j <= m; ++j) {
            if(ma[i][j] != ‘#‘) dp[i][j] = (dp[i][j] + dp[i - 1][j] + dp[i][j - 1]) % mod;
        }
    }
    LL ans1 = dp[n - 1][m] % mod, ans2 = dp[n][m - 1] % mod;
    memset(dp, 0, sizeof(dp));
    if(ma[2][1] != ‘#‘) dp[2][1]++;
    for(int i = 2; i <= n; ++i) {
        for(int j = 1; j <= m; ++j) {
            if(ma[i][j] != ‘#‘) dp[i][j] = (dp[i][j] + dp[i - 1][j] + dp[i][j - 1]) % mod;
        }
    }
    LL ans3 = dp[n - 1][m] % mod, ans4 = dp[n][m - 1] % mod;
    printf("%lld\n", ((ans4 * ans1) % mod - (ans2 * ans3) % mod + mod) % mod);
    return 0;
}

https://blog.csdn.net/ftx456789/article/details/81132126

牛客上的一个题。

原文地址:https://www.cnblogs.com/downrainsun/p/11220334.html

时间: 2024-10-10 23:06:01

Lindström–Gessel–Viennot lemma定理 行列式板子的相关文章

Nowcoder Monotonic Matrix ( Lindstr&#246;m–Gessel–Viennot lemma 定理 )

题目链接 题意 : 在一个 n * m 的矩阵中放置 {0, 1, 2} 这三个数字.要求 每个元素 A(i, j) <= A(i+1, j) && A(i, j) <= A(i, j+1) .问你合法的构造方案有多少种 分析 : 分析一下限制条件不难得出.其实就是在矩阵中设置两条分界线 使得分界线总左上角到右下角分别是 0.1.2 例如如下的矩阵就是合法的 0 0 1 2 0 1 2 2 1 2 2 2 那么问题就转化成了在矩阵中找出两条可重叠的路径 把矩阵分成三个部分 有一

Lindstr&#246;m–Gessel–Viennot lemma

(摘自知乎) Lindstr?m–Gessel–Viennot lemma(Lindstr?m-Gessel-Viennot lemma这里有详细介绍跟证明) 在一个有向无环图里,想要计算从n个起点 到n个终点 的n条互不相交的路径的数量(具体说是其生成函数),只要符合一定条件,就有个非常漂亮的形式表达出来.具体来说是下面一个矩阵M的行列式 其中 是从第i个起点到第j个终点的生成函数. 这里最神奇的一点是为什么结果是一个行列式.这个矩阵从线性空间的角度看完全没有意义,而实际证明过程中也完全是以组

【转】Lindstr&#246;m–Gessel–Viennot lemma 应用两则

原博客:http://www.cnblogs.com/jszkc/p/7309468.html 对于一张无边权的DAG图,给定n个起点和对应的n个终点,这n条不相交路径的方案数为 det() (该矩阵的行列式) 其中e(a,b)为图上a到b的方案数 codeforces 348D [给定一张n*m带障碍的图,求从左上角到右下角不相交两条路径的方案] [a1=(1,2) a2=(2,1) b1=(n-1,m) b2=(n,m-1) 应用该定理即可] HDU 5852 [给一张n*n的图,第一行m个

Codeforces 348 D - Turtles

D - Turtles 思路: LGV 定理 (Lindstr?m–Gessel–Viennot lemma) 从{\(a_1\),\(a_2\),...,\(a_n\)} 到 {\(b_1\),\(b_2\),...,\(b_n\)}的不相交路径数等于行列式 \[ {\left[ \begin{array}{ccc} c(a_1, b_1) & c(a_1, b_2) & ... & c(a_1, b_n) \c(a_2, b_1) & c(a_2, b_2) &

A Path Plan(2018黑龙江省赛)

又get 新知识 Lindström–Gessel–Viennot引理 改引理主要是解决n条严格不相交的路径的问题 其中ai代表路径的起点bi代表路径的终点e(ai,bj)代表ai到bj的方案数,答案是这个行列式的值 对于这道题而言,知道这个引理,这就是水题啊 code: #include <bits/stdc++.h> using namespace std; const int MOD = 1e9 + 7; typedef long long ll; const int N = 2e5 +

Matrix-Tree 定理

首先推荐 GJS学长 的这篇博文: http://www.cnblogs.com/meowww/p/6485422.html . Matrix-Tree 定理 度数矩阵 $D$ . $D_{i, i} = i 的度数$ . 邻接矩阵 $G$ . $G_{i, j}$ 表示 $i$ 到 $j$ 的连边数量. 基尔霍夫矩阵 $K$ , $K = D - G$ . 边矩阵 $B[m \times n]$ , 每行代表一条边, 对应位置的值为 $1$ . $B ^ T B = K$ . $B_i ^ T

组合数学漫游奇境记:Schur 多项式,Hook 长度公式,Macmahon 平面分拆公式

Young 表上的组合学是代数组合学中最奇妙的部分,与表示论,统计力学,概率论有着丰富而深刻的联系.这篇文章将从几个有趣的问题开始,带领大家走进这个美丽的领域.所需要的预备知识很少,学过线性代数即可,但是要真正领略其中风光,数学上的成熟是必不可少的. 需要事先剧透的是,本文要证明的几个定理绝非泛泛,它们都是代数组合学中的著名结论. 先来看几个问题: 有 $m$ 位总统候选人参加大选,他们每个人分别有 $\lambda_1,\ldots,\lambda_m$ 位支持者(假定选民只投票给他支持的候选

平面分拆的 Macmahon 公式

首先看一个计数问题:一个边长为 $a\times b\times c$ 的平行六边形,每个内角都是 120 度.用边长为 1 的菱形去覆盖,有多少种不同的方法? 比如下图就是一种: 我们从上方俯视这张图(虽然这是一个平面图形,但是我们想象在空间中鸟瞰它),发现它很像是在墙角堆箱子:在一个边长为 $a\times b\times c$ 的长方体空间中堆放若干形状为单位正方体的 "箱子".不仅如此,箱子堆放的规则是有限制的:紧贴墙角处的那一摞箱子最高,从墙角向外,箱子的高度是递减的.这个规

bzoj2982: combination(lucas定理板子)

2982: combination Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 664  Solved: 397[Submit][Status][Discuss] Description LMZ有n个不同的基友,他每天晚上要选m个进行[河蟹],而且要求每天晚上的选择都不一样.那么LMZ能够持续多少个这样的夜晚呢?当然,LMZ的一年有10007天,所以他想知道答案mod 10007的值.(1<=m<=n<=200,000,000) Inpu