LGV定理 (CodeForces 348 D Turtles)/(牛客暑期多校第一场A Monotonic Matrix)

又是一个看起来神奇无比的东东,证明是不可能证明的,这辈子不可能看懂的,知道怎么用就行了,具体看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|

其中

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

 

====================================分割线===============================================

========================================================================================

题目描述:

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.

输入描述:
The input consists of several test cases and is terminated by end-of-file.Each test case contains two integers n and m.
输出描述:
For each test case, print an integer which denotes the result.

这道题就没这么裸了,我们考虑01分界线和12分界线,都可以看作是从(n,0)出发,到(0,m)的两条路,而且根据题意这两条路不能相交,是不是和LGV很像了呢?然而LGV定理中路线重合也算相交,在这道题中路线是可以重合的,比如如果没有1只有0和2,那么01和12分界线是完全重合的,然后这道题很神奇的操作就是把01分界线向左向上移动了一格,这样两条路必然不会重合了(画画图),而且也变成了两个起点两个终点,

a1 = (n-1, -1)  a2 = (n, 0)
b1 = (-1, m-1) b2 = (0, m)

经过这个神奇的操作后就直接套用LGV就行了.....因为这题不像上一道CF路径中间有障碍,所以求方法数只要简单的用排列组合+阶乘逆元就行了(比如(n,0)--->(0,m),一共要走n+m步,其中选n步向上,选m步向右,就是算个组合数了)

 1 #include <iostream>
 2 #include <string.h>
 3 #include <cstdio>
 4 #include <vector>
 5 #include <queue>
 6 #include <stack>
 7 #include <math.h>
 8 #include <string>
 9 #include <algorithm>
10 #include <functional>
11 
12 #define SIGMA_SIZE 26
13 #define lson rt<<1
14 #define rson rt<<1|1
15 #define lowbit(x) (x&-x)
16 #define foe(i, a, b) for(int i=a; i<=b; i++)
17 #define fo(i, a, b) for(int i=a; i<b; i++)
18 #define pii pair<int,int>
19 #pragma warning ( disable : 4996 )
20 
21 using namespace std;
22 typedef long long LL;
23 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
24 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
25 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
26 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
27 inline int Max(int a, int b) { return a>b ? a : b; }
28 inline int Min(int a, int b) { return a>b ? b : a; }
29 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
30 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
31 const LL INF = 0x3f3f3f3f3f3f3f3f;
32 const LL mod = 1e9+7;
33 const double eps = 1e-8;
34 const int inf = 0x3f3f3f3f;
35 const int maxk = 3e6 + 5;
36 const int maxn = 2010;
37 
38 LL fac[maxn];
39 LL inv[maxn];
40 
41 LL quickPow(LL a, LL b, LL m)
42 {
43     LL ans = 1, base = a;
44     while (b) {
45         if (b & 1)
46             ans = (ans*base) % m;
47         base = (base*base) % mod;
48         b >>= 1;
49     }
50     return ans;
51 }
52 
53 void init()
54 {
55     fac[0] = fac[1] = 1;
56     inv[0] = inv[1] = 1;
57 
58     for( int i = 2; i < maxn; i++ )
59         fac[i] = (fac[i-1]*i) % mod;
60 
61     inv[maxn-1] = quickPow(fac[maxn-1], mod-2,mod);
62     for( int i = maxn-2; i >= 2; i-- )
63         inv[i] = (inv[i+1]*(i+1)) % mod;
64 }
65 
66 LL C(int up, int down)
67 {
68     if (up > down) return 0;
69     return fac[down]*inv[down-up]%mod*inv[up]%mod;
70 }
71 
72 
73 //a1 = (n-1, -1) a2 = (n, 0)
74 //b1 = (-1, m-1) b2 = (0, m)
75 int main()
76 {
77     init();
78     int row, col;
79     while (~scanf("%d %d", &row, &col))
80     {
81          LL x1, x2, x3, x4;
82          x1 = C(row, row+col);
83          x2 = C(col+1, row+col);
84          x3 = C(col-1, row+col);
85          x4 = x1;
86 
87          LL ans = ((x1*x4)%mod - (x2*x3)%mod + mod) % mod;
88          printf("%lld\n", ans);
89     }
90 
91     return 0;
92 }
View Code

 

posted @ 2018-08-11 17:17  LBNOQYX  阅读(1095)  评论(0编辑  收藏  举报