Lindström–Gessel–Viennot lemma定理 (附 HDU 5852(level 3)(高斯消元求行列式+LGV定理)+牛客多校第一场 A)

 

 

下面是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}的一种排列(类似于置换群的概念)

 

Lindström–Gessel–Viennot lemma定理 (附 HDU 5852(level 3)(高斯消元求行列式+LGV定理)+牛客多校第一场 A)_第1张图片

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
Next line contains K integers: 1<=b1

 

 

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

最后一行有n个终点1<=b1

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

答案mod 1e9+7

 

解析:

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

\begin{pmatrix} C_{n+b_{1}-(1+a_{1})}& C_{n+b_{2}-(1+a_{1})}& C_{n+b_{3}-(1+a_{1})}& ...& C_{n+b_{k}-(1+a_{1})} \\ C_{n+b_{1}-(1+a_{2})}& C_{n+b_{2}-(1+a_{2})}& C_{n+b_{3}-(1+a_{2})}& ...& C_{n+b_{k}-(1+a_{2})} \\ ...& ... &... & ... &... \\ C_{n+b_{1}-(1+a_{k})}& C_{n+b_{2}-(1+a_{k})}& C_{n+b_{3}-(1+a_{k})}& ...& C_{n+b_{k}-(1+a_{k})} \end{pmatrix}

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

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

#include 
#include 
#include 
#include 
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

牛客网暑期ACM多校训练营(第一场)

A Monotonic Matrix

题意:

Count the number of n x m matrices A satisfying the following condition modulo (109+7). 
* Ai, j ∈ {0, 1, 2} for all 1 ≤ i ≤ n, 1 ≤ j ≤ m. 
* Ai, j ≤ Ai + 1, j for all 1 ≤ i < n, 1 ≤ j ≤ m. 
* Ai, j ≤ Ai, j + 1 for all 1 ≤ i ≤ n, 1 ≤ j < m.

 

解析:

找到LGV定理之后,难点是怎么找到阶梯型。

我目前做的3道LGV的题目,关键都是在图中找出阶梯型的线。

这里你随便画一个填充0,1,2的矩阵后会发现,每一次变换的地方会形成左下到右上的阶梯型(0->1,0->2,1->2)

PS:这个我找了半天才发现.....

Lindström–Gessel–Viennot lemma定理 (附 HDU 5852(level 3)(高斯消元求行列式+LGV定理)+牛客多校第一场 A)_第2张图片

那么我们就把0的边界和2的边界作为两条路径,这样问题就变成了从(0,m)->(n,0),(1,m+1)->(n+1,1)找两条不相交的路径

这个就直接套LGV的行列式\begin{pmatrix} C_{n+m}^{n} &C_{n+m}^{n+1} \\ C_{n+m}^{n-1}& C_{n+m}^{n} \end{pmatrix}

算出这个行列式的值就是答案了

下面有几个图,大家可以理解一下

Lindström–Gessel–Viennot lemma定理 (附 HDU 5852(level 3)(高斯消元求行列式+LGV定理)+牛客多校第一场 A)_第3张图片

Lindström–Gessel–Viennot lemma定理 (附 HDU 5852(level 3)(高斯消元求行列式+LGV定理)+牛客多校第一场 A)_第4张图片

Lindström–Gessel–Viennot lemma定理 (附 HDU 5852(level 3)(高斯消元求行列式+LGV定理)+牛客多校第一场 A)_第5张图片

#include 
#include 
#include 
#include 
using namespace std;
typedef long long int ll;

const int MAXN = 2e3+10;
ll jc[MAXN];
ll inv[MAXN];
const ll MOD = 1e9+7;

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

 

 

 

 

 

你可能感兴趣的:(数学题)