Nowcoder Monotonic Matrix ( Lindström–Gessel–Viennot lemma 定理 )
题意 : 在一个 n * m 的矩阵中放置 {0, 1, 2} 这三个数字、要求 每个元素 A(i, j) <= A(i+1, j) && A(i, j) <= A(i, j+1) 、问你合法的构造方案有多少种
分析 :
分析一下限制条件不难得出、其实就是在矩阵中设置两条分界线
使得分界线总左上角到右下角分别是 0、1、2 例如如下的矩阵就是合法的
0 0 1 2
0 1 2 2
1 2 2 2
那么问题就转化成了在矩阵中找出两条可重叠的路径
把矩阵分成三个部分
有一个 Lindström–Gessel–Viennot lemma 定理就是专门做这件事情的
具体可以看看这篇博客 ==> click here
但是这个定理只适用于不相交的路径
但是我们这个题目下路径是可以重叠的、也算相交的一种
那么需要采用等价转化的方法来避免相交
此题可以采用将第二条路径整体平移的方法、将终点和起点都整体向右下平移
这并不会干扰方案数、然后根据平移后的起点终点就能计算行列式了 ==> click here
#include<bits/stdc++.h> #define LL long long #define ULL unsigned long long #define scl(i) scanf("%lld", &i) #define scll(i, j) scanf("%lld %lld", &i, &j) #define sclll(i, j, k) scanf("%lld %lld %lld", &i, &j, &k) #define scllll(i, j, k, l) scanf("%lld %lld %lld %lld", &i, &j, &k, &l) #define scs(i) scanf("%s", i) #define sci(i) scanf("%d", &i) #define scd(i) scanf("%lf", &i) #define scIl(i) scanf("%I64d", &i) #define scii(i, j) scanf("%d %d", &i, &j) #define scdd(i, j) scanf("%lf %lf", &i, &j) #define scIll(i, j) scanf("%I64d %I64d", &i, &j) #define sciii(i, j, k) scanf("%d %d %d", &i, &j, &k) #define scddd(i, j, k) scanf("%lf %lf %lf", &i, &j, &k) #define scIlll(i, j, k) scanf("%I64d %I64d %I64d", &i, &j, &k) #define sciiii(i, j, k, l) scanf("%d %d %d %d", &i, &j, &k, &l) #define scdddd(i, j, k, l) scanf("%lf %lf %lf %lf", &i, &j, &k, &l) #define scIllll(i, j, k, l) scanf("%I64d %I64d %I64d %I64d", &i, &j, &k, &l) #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #define lowbit(i) (i & (-i)) #define mem(i, j) memset(i, j, sizeof(i)) #define fir first #define sec second #define VI vector<int> #define ins(i) insert(i) #define pb(i) push_back(i) #define pii pair<int, int> #define VL vector<long long> #define mk(i, j) make_pair(i, j) #define all(i) i.begin(), i.end() #define pll pair<long long, long long> #define _TIME 0 #define _INPUT 0 #define _OUTPUT 0 clock_t START, END; void __stTIME(); void __enTIME(); void __IOPUT(); using namespace std; const int maxn = 2e3 + 10; const LL mod = 1e9 + 7; LL c[maxn][maxn]; inline void init() { for(int i=1; i<=maxn-10; i++){ c[i][0] = c[i][i] = 1; for(int j=1; j<i; j++){ c[i][j] = (c[i-1][j]%mod + c[i-1][j-1]%mod)%mod; } } } int main(void){__stTIME();__IOPUT(); int n, m; init(); while(~scii(n, m)){ printf("%lld\n", ( ( (c[n+m][n]%mod * c[n+m][n]%mod)%mod - (c[n+m][m-1]%mod * c[n+m][m+1]%mod)%mod ) + mod ) % mod); } __enTIME();return 0;} void __stTIME() { #if _TIME START = clock(); #endif } void __enTIME() { #if _TIME END = clock(); cerr<<"execute time = "<<(double)(END-START)/CLOCKS_PER_SEC<<endl; #endif } void __IOPUT() { #if _INPUT freopen("in.txt", "r", stdin); #endif #if _OUTPUT freopen("out.txt", "w", stdout); #endif }