牛客网暑期ACM多校训练营(第一场) A.Monotonic Matrix (不相交路径Lindström–Gessel–Viennot lemma定理+组合数)

题目链接

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

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

输入

1 2
2 2
1000 1000

输出

6
20
540949876

备注:

* 1 ≤ n, m ≤ 103
* The number of test cases does not exceed 105.

题意:给出一个N*M的矩阵,要求在其中填入{0,1,2},且需要满足,问可以弄出多少个这样的矩阵,结果数对mod=1e9+7取模.

思路:从题目可以知道这是一个填字游戏,对于只有2种数的情况下分析,那么矩阵将会被一条如下图的线分为2部分:

                                            

        那么对于这条分界线来说就是可以认为是从起点(n,0)到终点(0,m)的一条非降路径,可以知道转换为组合数情况数有C_{n+m}^{m}C_{n+m}^{n}种.

而对于有3种数字满足题目条件就很容易发现是再多一条分界线如下图:

                                            

        现在得到的是2条可重合路径,可以将矩阵分为2份或3份.如果不考虑2他们相交的情况一共有C_{n+m}^{m}*C_{n+m}^{m}种情况,那么下面考虑如何去重:

        这里由于Lindström–Gessel–Viennot lemma定理可以直接求得完全不想交的路径数,所以我们只需要将其中一条路径的起点和终点都向左下方平移一个单位长度即可(如下图),那么问题将装换为2条完全不想交的路径数求解问题,套用定理公式即可~

                                             

题解:根据Lindström–Gessel–Viennot引理我们就可以求出n条严格不相交的路径的方案数 

            


       其中ai,bi都表示的是一个坐标点,e是以ai为起点,bi为终点的情况数,最终求出的M就是答案了;

那么对于本题只有2条路径,因此有2个起点和2个终点如下:

         [路径一]  : a1=(n,0),b1=(0,m)         [路径二] : a2=(n−1,−1),b2=(−1,m−1)
所以答案就是 

                      M=\begin{vmatrix} e(a1,b1)& e(a1,b2)\\ e(a2,b1)& e(a2,b2) \end{vmatrix}=\begin{vmatrix} C_{n+m}^{n} &C_{n+m}^{n+1} \\ C_{n+m}^{n-1}& C_{n+m}^{n} \end{vmatrix}=C_{n+m}^{n}^2-C_{n+m}^{n+1}* C_{n+m}^{n-1}

然后打标预处理出题目数据范围内所有组合数的结果即可~

代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<vector>
using namespace std;
#define ll long long
const int maxn = 2e3 + 10;
const ll mod = 1e9 + 7;
ll C[maxn][maxn];
void get_C() {                  
	for (int i = 0; i <= 2e3; i++) {
		C[i][0] = 1;
		for (int j = 1; j <= i; j++)
			C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
	}
}
int main(){
	get_C();
	int n, m;
	while (~scanf("%d%d", &n, &m)) {
		ll ans = C[n + m][n] * C[n + m][n] - C[n + m][n + 1] * C[n + m][n - 1];
		ans = (ans%mod + mod) % mod;
		printf("%lld\n", ans);
	}
	return 0;
}

参考资料:https://en.wikipedia.org/wiki/Lindstr%C3%B6m%E2%80%93Gessel%E2%80%93Viennot_lemma

猜你喜欢

转载自blog.csdn.net/weixin_41156591/article/details/81205085
今日推荐