https://en.wikipedia.org/wiki/Lindström–Gessel–Viennot_lemma
两个人从 (0, 0)走到 (n, m) 要求除了起点和终点不能相遇
转化:
从(1,0)走到(n,m-1),方案数是 C(n+m-2,n-1)
从(0,1)走到(n-1,m),方案数是 C(n+m-2,n-1)
但其中有一些方案,两个人的路线相交了,计算相交的方案数
从(1,0)走到(n-1,m),方案数是 C(n+m-2,m)
从(0,1)走到(n,m-1),方案数是 C(n+m-2,n)
最终答案是
C(n+m-2,n-1) * C(n+m-2,m-1) - C(n+m-2,m) * C(n+m-2,n)
https://codeforces.com/problemset/problem/348/D
https://www.luogu.com.cn/problem/CF348D
#include <bits/stdc++.h> using namespace std; const int p = 1000000007; int n, m; char s[3020]; int f[3020][3020]; // from (1, 2) to every other point int g[3020][3020]; // from (2, 1) to every other point int main() { ios::sync_with_stdio(false); cin >> n >> m; f[0][2] = 1; g[2][0] = 1; for (int i = 1; i <= n; i++) { cin >> s; for (int j = 1; j <= m; j++) { if (s[j - 1] == '.') { f[i][j] = (f[i - 1][j] + f[i][j - 1]) % p; g[i][j] = (g[i - 1][j] + g[i][j - 1]) % p; } } } cout << ((long long)f[n - 1][m] * g[n][m - 1] % p + p - (long long)g[n - 1][m] * f[n][m - 1] % p) % p << endl; return 0; }
https://www.luogu.com.cn/problem/P6657
这是一道模板题。
有一个 的棋盘,左下角为 ,右上角为 ,若一个棋子在点 ,那么走一步只能走到 或 。
现在有 个棋子,第 个棋子一开始放在 ,最终要走到 。问有多少种方案,使得每个棋子都能从起点走到终点,且对于所有棋子,走过路径上的点互不相交。输出方案数 的值。
两种方案不同当且仅当存在至少一个棋子所经过的点不同。
本题有多组数据
第一行一个整数 ,表示该测试点的数据组数。
对于每组数据:
第一行两个整数 ,分别表示棋盘的大小和起点终点的数量。
接下来 行,每行 个整数 ,其意义已在题目描述中说明。
对于每一组数据,输出一行一个整数表示方案数 的值。
3
3 2
1 2
2 3
5 2
1 3
3 5
10 5
3 5
4 7
5 8
7 9
9 10
3
155
2047320
对于 的数据,,。
对于 的数据,,,,,。
#include <bits/stdc++.h> using namespace std; const int mod = 998244353; int t, n, m; int a[100][100]; int x[100]; int y[100]; int f[2000020]; int v[2000020]; int C(int n, int m) { return n < m ? 0 : (long long)f[n] * v[m] % mod * v[n - m] % mod; } int main() { v[0] = v[1] = f[0] = 1; for (int i = 2; i < 2000010; i++) { v[i] = (long long)(mod - mod / i) * v[mod % i] % mod; } for (int i = 1; i < 2000010; i++) { f[i] = (long long)f[i - 1] * i % mod; v[i] = (long long)v[i - 1] * v[i] % mod; } scanf("%d", &t); for (int tt = 0; tt < t; tt++) { scanf("%d%d", &m, &n); for (int i = 0; i < n; i++) { scanf("%d%d", &x[i], &y[i]); } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { a[i][j] = C(m - 1 + y[j] - x[i], m - 1); } } int ans = 1; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { while (a[j][i]) { int t = a[i][i] / a[j][i]; for (int k = 0; k < n; k++) { a[i][k] = (a[i][k] - (long long)a[j][k] * t) % mod; } swap(a[i], a[j]); ans = -ans; } } ans = (long long)ans * a[i][i] % mod; } if (ans < 0) { ans += mod; } printf("%d\n", ans); } return 0; }