LGV算法 CodeForces 348D + 牛客多校 A Monotonic Matrix

定理(Lindström–Gessel–Viennot lemma)很简单:

学的时候忘了大的行列式怎么算的了。。

 

 

 然后就可以写题了:

第一道:CodeForces-348D(链接https://vjudge.net/problem/CodeForces-348D)

题意给你个n*m的方阵,有一些点无法通过,然后求从(1,1)到(n,m)走两条路,并且两条路不相交的方案数。

题解:只能向右或者向下走,那么起始点肯定一个向左一个向右,结束点肯定一个从上方过来,一个从左方过来,那么题就成了两个点(1,2)(2,1)到两个点(n-1,m)(n,m-1)。就能写了。

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define met(a, b) memset(a, b, sizeof(a))
#define rep(i, a, b) for(int i = a; i <= b; i++)
#define bep(i, a, b) for(int i = a; i >= b; i--)
#define re return 0
using namespace std;
const ll mod = 1e9 + 7;
const double PI = acos(-1);
const ll INF = 2e18+1;
const int inf = 1e9 + 15;
const double eps = 1e-7;
const int maxn = 1e6 + 5;
ll d[3003][3003], p[3003][3003];
string ma[3003];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int n, m; cin >> n >> m;
    n--, m--;
    rep(i, 0, n) cin >> ma[i];
    d[0][0] = p[0][0] = 1;
    rep(i, 0, n){
        rep(j, 1, m){
            if(ma[i][j] == '.'){
                if(i) d[i][j] += d[i-1][j];
                if(j) d[i][j] += d[i][j-1];
                d[i][j] %= mod;
            }
        }
    }
    rep(i, 1, n){
        rep(j, 0, m){
            if(ma[i][j] == '.'){
                if(i) p[i][j] += p[i-1][j];
                if(j) p[i][j] += p[i][j-1];
                p[i][j] %= mod;
            }
        }
    }
    cout << ((d[n-1][m]*p[n][m-1])%mod - (d[n][m-1]*p[n-1][m])%mod + mod) % mod << endl;
    re;
}

 

牛客多校的题Monotonic Matrix (链接https://vjudge.net/problem/Gym-247727A)

题意:n*m的格子,每个格子可以填0,1,2,要求保证每行每列都是非递减,求可填充的方案数。

题解:

直接上图

也就是找两条线,一条01分割线,一条12分割线。这样就和LGV有联系了,但是LGV求的是不相交(重合也不行),而这题是可以重合的。如下图

 为了能用LGV必须让上图变成不重合的,那么就可以平移一个线,可以把红线的起始点终点向左向上平移一格或者把蓝线的起始点终点向右向下平移一个格

我们平移红线,就变成了:

可以发现其实变成了这样:这种可以用LGV求出来不相交的,就等价于上边含有重合的。如果不太理解可以想一下这种求出来的所有方案的情景,把红色向右下移动一格,不就是含有重合的所有方案数吗。

 

然后可以直接写了,行列式就是,组合数直接得出每个的方案数 = c[n+m][n]*c[n+m][n] - c[n+m][n-1]*c[n+m][n+1];

 

code:

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define met(a, b) memset(a, b, sizeof(a))
#define rep(i, a, b) for(int i = a; i <= b; i++)
#define bep(i, a, b) for(int i = a; i >= b; i--)
#define pb push_back
#define mp make_pair
#define debug cout << "KKK" << endl
#define ls num*2
#define rs num*2+1
#define re return 0
using namespace std;
const ll mod = 1e9 + 7;
const double PI = acos(-1);
const ll INF = 2e18+1;
const int inf = 1e9 + 15;
const double eps = 1e-7;
const int maxn = 1e6 + 5;
ll c[2005][1111];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    c[0][0] = 1;
    rep(i, 1, 2000){
        c[i][0] = 1;
        rep(j, 1, min(i, 1005)){
            c[i][j] = (c[i-1][j] + c[i-1][j-1]) % mod;
        }
    }
    int n, m;
    while(cin >> n >> m){
        cout << ((c[n+m][n]*c[n+m][n])%mod - (c[n+m][n-1]*c[n+m][n+1])%mod + mod) % mod << endl;
    }
    re;
}

 

posted @ 2020-05-15 09:46  philo_zhou  阅读(371)  评论(0编辑  收藏  举报