牛客网多校训练第一场 A - Monotonic Matrix(Lindström–Gessel–Viennot lemma)
链接:
https://www.nowcoder.com/acm/contest/139/A
题意:
求满足以下条件的n*m矩阵A的数量模(1e9+7):
A(i,j) ∈ {0,1,2}, 1≤i≤n, 1≤j≤m.
A(i,j) ≤ A(i+1,j), 1≤i<n, 1≤j≤m.
A(i,j) ≤ A(i,j+1), 1≤i≤n, 1≤j<m.
其中1 ≤ n,m ≤ 1e3。
分析:
考虑01和12的分界线,
是(n,0)到(0,m)的两条不相交(可重合)路径。
平移其中一条变成(n+1,1)到(1,m+1),
变成(n,0)到(0,m)、(n+1,1)到(1,m+1)的严格不相交路径。
套Lindström–Gessel–Viennot lemma,
答案是C(n+m,n) * C(n+m,n) - C(n+m,n+1) * C(n+m,n-1)。
Lindström–Gessel–Viennot lemma简介:
求a1到b1, a2到b2, ..., an到bn的严格不相交路径种数。
计算以上矩阵的行列式即可,其中e(a,b)是从a到b的方法数。
代码:
1 #include <cstdio> 2 3 typedef long long int LLI; 4 const int UP = 1000 * 2 + 5; 5 const LLI MOD = 1e9 + 7; 6 LLI f[UP]; // 阶乘 7 8 LLI qmod(LLI x, LLI n, LLI mod) { // 快速幂模 9 x %= mod; 10 LLI res = 1; 11 while(n) { 12 if(n & 1) res = res * x % mod; 13 n >>= 1; 14 x = x * x % mod; 15 } 16 return res; 17 } 18 19 LLI inv(LLI a, LLI mod) { // 逆元 20 return qmod(a, mod-2, mod); 21 } 22 23 void constant() { // 预处理阶乘 24 f[0] = 1; 25 for(int i = 1; i < UP; i++) f[i] = f[i-1] * i % MOD; 26 } 27 28 LLI C(int n, int m) { // 组合数,从n个里取m个 29 return f[n] * inv(f[m]*f[n-m], MOD) % MOD; 30 } 31 32 int main() { 33 constant(); 34 int n, m; 35 while(~scanf("%d%d", &n, &m)) { 36 LLI ans = (C(n+m,n) * C(n+m,n) - C(n+m,n+1) * C(n+m,n-1) % MOD + MOD) % MOD; 37 printf("%lld\n", ans); 38 } 39 return 0; 40 }