cf348D. Turtles(LGV定理 dp)

题意

题目链接

\(n \times m\)有坏点的矩形中找出两条从起点到终点的不相交路径的方案数

Sol

Lindström–Gessel–Viennot lemma的裸题?

这个定理是说点集\(A = \{a_1, a_2, \dots a_n \}\)\(B = \{b_1, b_2, \dots b_n \}\)的不相交路径条数等于

\[\begin{bmatrix} e(a_1, b_1) & e(a_1, b_2) & \dots & e(a_1, b_n) \\ e(a_2, b_1) & e(a_2, b_2) & \dots & e(a_2, b_n) \\ \dots & \dots & \dots & \dots \\ e(a_n, b_1) & e(a_n, b_2) & \dots & e(a_n, b_n) \\ \end{bmatrix} \]

的行列式的值。其中\(e(x, y)\)表示从\(x\)\(y\)的路径条数

定理的本质还是容斥

回归到本题,我们需要找到两条不相交的路径。注意到任何一对合法的路径一定是一条从\((1, 2)\)出发到\((n - 1, m)\),另一条从\((2, 1)\)出发到\((n, m - 1)\)

那么选取\(A = \{(1, 2) \ (2, 1)\}, B = \{(n - 1, m) \ (n, m - 1)\}\)

带入到上述定理即可求解

#include<bits/stdc++.h> 
#define Pair pair<int, int>
#define MP(x, y) make_pair(x, y)
#define fi first
#define se second
#define int long long 
#define LL long long 
#define pt(x) printf("%d ", x);
#define Fin(x) {freopen(#x".in","r",stdin);}
#define Fout(x) {freopen(#x".out","w",stdout);}
using namespace std;
const int MAXN = 3001, INF = 1e9 + 10, mod = 1e9 + 7;
const double eps = 1e-9;
void chmax(int &a, int b) {a = (a > b ? a : b);}
void chmin(int &a, int b) {a = (a < b ? a : b);}
int sqr(int x) {return x * x;}
int add(int x, int y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
void add2(int &x, int y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
int mul(int x, int y) {return 1ll * x * y % mod;}
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int C[MAXN][MAXN], N, M;
char A[MAXN][MAXN];
int f(int a, int b, int c, int d) {
    memset(C, 0, sizeof(C));
    for(int i = a; i <= c; i++) 
        for(int j = b; j <= d; j++) 
            if(A[i][j] == '.') {
                if(i == a && j == b) C[i][j] = 1;
                else  C[i][j] = add(C[i - 1][j], C[i][j - 1]);              
            }

    return C[c][d];
}
void solve() {
    N = read(); M = read();
    for(int i = 1; i <= N; i++) scanf("%s", A[i] + 1);
    cout << add(mul(f(1, 2, N - 1, M), f(2, 1, N, M - 1)), -mul(f(1, 2, N, M - 1), f(2, 1, N - 1, M))) << '\n';
}
signed main() {
    for(int T = 1; T; T--, solve());
    return 0;
}
posted @ 2018-12-29 14:27  自为风月马前卒  阅读(626)  评论(0编辑  收藏  举报

Contact with me