LGV定理相关

又是一个看起来神奇无比的东东,证明是不可能证明的,这辈子不可能看懂的,知道怎么用就行了,具体看wikihttps://en.wikipedia.org/wiki/Lindstr%C3%B6m%E2%80%93Gessel%E2%80%93Viennot_lemma

LGV定理就是求n个起点到n个终点(且一个起点对应一个终点)的不相交路径数目的一种方法,光看这句话不好理解,来看一道cf题

CodeForces - 348D Turtles

这道题给你一个n*m的矩阵(1~n, 1~m),现在有两只乌龟都从左上角(1,1)出发,到达右下角(n,m),乌龟每次只能往右或者往下走一格,且两只乌龟走的路径不能交叉,问一共有多少种走法。首先显然可知的是一只乌龟必然从(1,2)走到(n-1, m),另一只必然从(2,1)走到(n,m-1),这个画画图就知道很显然了,那么我们可以看作有两个2个起点,2个终点,问共多少种不相交路径,这就是LGV定理了。

LGV定理实际上是求一个行列式

ai是起点,bi是终点,e(ai, bj)代表从ai为起点到bj为终点的方法数目,特别的注意ai对应bi(就是我们想求的起点到终点的方案数)

那么对于这道题,就相当于求一个2x2行列式的值。

|e1,   e2|

|e3,   e4|

其中

扫描二维码关注公众号,回复: 2698668 查看本文章

e1 =  a1(2,1)-->b1(n,m-1) 的方案数

e2 =  a1(2,1)-->b2(n-1,m) 的方案数

这两个用一遍dp求出来

e3 = a2(1,2)-->b1n,m-1) 的方案数

e4 = a2(1,2)-->b2(n-1,m) 的方案数

这两个也用一遍dp求出来

然后只要代入行列式,就能求得a1-b1,a2-b2且路径不相交的方法数ans=(e1*e4-e2*e3)了

#include <iostream>
#include <string.h>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <math.h>
#include <string>
#include <algorithm>
#include <functional>

#define SIGMA_SIZE 26
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) (x&-x)
#define foe(i, a, b) for(int i=a; i<=b; i++)
#define fo(i, a, b) for(int i=a; i<b; i++)
#define pii pair<int,int>
#pragma warning ( disable : 4996 )

using namespace std;
typedef long long LL;
inline LL LMax(LL a, LL b) { return a>b ? a : b; }
inline LL LMin(LL a, LL b) { return a>b ? b : a; }
inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
inline int Max(int a, int b) { return a>b ? a : b; }
inline int Min(int a, int b) { return a>b ? b : a; }
inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = 1e9+7;
const double eps = 1e-8;
const int inf = 0x3f3f3f3f;
const int maxk = 3e6 + 5;
const int maxn = 7e7 + 5;

bool g[3010][3010];
int row, col;
char str[3010];
LL dp[3010][3010];

void init()
{
    cin >> row >> col;

    for (int i = 1; i <= row; i++ )
    {
        scanf("%s", str+1);
        for ( int j = 1; j <= col; j++ ) {
            if (str[j]=='#')
                g[i][j] = true;
        }
    }
}

pair<LL, LL> getRoad(int x, int y)
{
    memset(dp, 0, sizeof(dp));
    dp[1][1] = 1;
    for (int i = x; i <= row; i++)
    {
        for (int j = y; j <= col; j++) {
            if (!g[i][j])
                dp[i][j] = (dp[i][j]+dp[i-1][j]+dp[i][j-1])%mod;
        }
    }
    return make_pair(dp[row][col-1], dp[row-1][col]);
}

int main()
{
    init();

    LL x1, x2, x3, x4;
    pair<LL, LL> tmp;
    
    tmp = getRoad(2, 1);
    x1 = tmp.first; x2 = tmp.second;
    tmp = getRoad(1, 2);
    x3 = tmp.first; x4 = tmp.second;

    LL ans = ((x1*x4)%mod-(x2*x3)%mod+mod)%mod;
    printf("%lld\n", ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/chaoswr/p/9460378.html