CodeForces - 348D Turtles【DP+LGV】

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

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

#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;
}

猜你喜欢

转载自blog.csdn.net/qq_36368339/article/details/81133921