牛客多校第一场A——Monotonic Matrix(数论——组合数学—— Lindström–Gessel–Viennot lemma )

这题在打比赛时,我感觉到了来自于世界的恶意。。。 Lindström–Gessel–Viennot lemma定理,在比赛前,我是完全没有听说过的,好想哭,挂机的数论选手。。。

1. 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. 备注 * 1 ≤ n, m ≤ 103 * The number of test cases does not exceed 10 5.
示例1:

输入

1 2

2 2

1000 1000

输出

6

20

540949876

目录

Lindström–Gessel–Viennot Lemma

AC代码:


题意:一个n x m 的矩阵,填入0,1,2三个数字,每行每列下标大的数字要填入大于等于前一个数字的值。

思路:将填入0,1和1,2看成两条不同的路,通过Lindström–Gessel–Viennot Lemma来计算其中不同路径的条数

Lindström–Gessel–Viennot Lemma

作为一个特殊情况,引理提供对给定一个起点终点对集(记起点集为 AA 终点集为 BB ,且路径为 ai→biai→bi ),统计不相交路径数。

引理的内容如下:

令 ω(P):=ω(P):= 路径 PP 的边权积, e(a,b):=∑P:a→bω(P)e(a,b):=∑P:a→bω(P) ,

M:=(e(a1,b1)e(a1,b2)⋯e(a1,bm) e(a2,b1)e(a2,b2)⋯e(a2,bm) ⋮⋮⋱⋮ e(an,b1)e(an,b2)⋯e(an,bm))M:=(e(a1,b1)e(a1,b2)⋯e(a1,bm) e(a2,b1)e(a2,b2)⋯e(a2,bm) ⋮⋮⋱⋮ e(an,b1)e(an,b2)⋯e(an,bm))


该引理宣称,det|M|det|M| 给出AA 到 BB 不相交路径的权值和。

特殊情况,令各边边权为11 ,此时|M||M| 为不相交路径数。

更一般情况,ωω 可以是形式变量,则 ee 将成为形式幂级数。

假定我们在网格图中,从第 11 行的起点走到第 nn 的终点。

首先假设我们只有两对点 (a1,b1),(a2,b2)(a1,b1),(a2,b2) ,不考虑相交,则总路径数为 (b1−a1+n−1n−1)(b2−a2+n−1n−1)(b1−a1+n−1n−1)(b2−a2+n−1n−1) .

考虑 a1→b1,a2→b2a1→b1,a2→b2 相交,则在最后一个相交点之后交换路径,则得到 a1→b2,a2→b1a1→b2,a2→b1 的路径。

考虑 a1→b2,a2→b1a1→b2,a2→b1 的路径,其必相交,则在最后一个相交点之后交换路径。

此时我们建立了 a1→b1,a2→b2a1→b1,a2→b2 的相交路径与 a1→b2,a2→b1a1→b2,a2→b1 的一一对应。

所以除去不合法情况后,答案为 (b1−a1+n−1n−1)(b2−a2+n−1n−1)−(b1−a2+n−1n−1)(b2−a1+n−1n−1)(b1−a1+n−1n−1)(b2−a2+n−1n−1)−(b1−a2+n−1n−1)(b2−a1+n−1n−1) .

接着考虑多组路径,使用容斥原理。

假设某些路径相交,则在最后一个相交点之后交换路径,得到 BB 的重排 CC .

所以我们只需考虑 CC 的逆序对数,为奇数则贡献为负,否则为正。

展开写,发现这就是一个行列式。

把对应的组合数换为路径数的记号的话,就是引理的内容了,证明同理。

后面补题的时候,也是极其难受。。。表示查了好多东西才看明白。。。

AC代码:

#include<bits/stdc++.h>
#include<ctime>
using namespace std;
const int N = 2e3 + 7;
const int mod = 1e9 + 7;
long long jie[N],ni[N];
void get_jie()
{
    jie[0] = 1;
    for(int i = 1; i < N;++i)   jie[i] = (jie[i - 1] * i) % mod;
}
long long fpow_mod(long long a,long long b)
{
    long long res = 1;
    while(b){
        if(b & 1) res = (res * a) % mod;;
        a = (a * a) % mod;
        b >>= 1;
    }
    return res;
}
void get_inv()
{
    for(int i = 0;i < N;++i)
        ni[i] = fpow_mod(jie[i],mod - 2);
}
inline long long con(int n,int m)
{
    return (jie[n] * ni[m]) % mod * ni[n - m] % mod;
}
int main()
{
    int n,m;
    get_jie();
    get_inv();
    while(cin >> n >> m){
        long long ans = 0;
        ans = con(n + m,n);
        ans = (ans * ans) % mod;
        ans = ans - (con(n + m,m - 1) * con(n + m,n - 1)) % mod;
        /*if(n == 1 || m == 1){
            if(n < m) swap(n,m);
            ans = 2 + n + (n + 2) * (n - 1) / 2;
        }*/
        ans = (ans + mod) % mod;
        cout << ans << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41791981/article/details/81126038
今日推荐