题意 : 给定方格中第一行的各个起点、再给定最后一行与起点相对应的终点、问你从这些起点出发到各自的终点、不相交的路径有多少条、移动方向只能向下或向右
分析 :
首先对于多起点和多终点的不相交路径、有一个LGV定理
实际上就是 n^2 构造矩阵、再计算其行列式
矩阵的构造方法可以看看这个 ==> Click here
那么接下来就是确定各自路径的方案数了
这是一个经典问题
这里需要求解组合数、用预处理阶乘逆元的方法即可求出
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> #define LL long long using namespace std; const int Comb_Maxn = 2e5 + 10; const LL mod = 1e9 + 7; LL Fac_inv[Comb_Maxn]; LL Fac[Comb_Maxn]; inline void Comb_init() { Fac_inv[0] = Fac[0] = 1; Fac_inv[1] = 1; for(int i=1; i<Comb_Maxn; i++) Fac[i] = Fac[i-1] * (LL)i % mod; for(int i=2; i<Comb_Maxn; i++) Fac_inv[i] = (LL)(mod - mod / i) * Fac_inv[mod % i] % mod; for(int i=1; i<Comb_Maxn; i++) Fac_inv[i] = Fac_inv[i-1] * Fac_inv[i] % mod; } LL Comb(int n, int m) { return Fac[n] * Fac_inv[m] % mod * Fac_inv[n-m] % mod; } const int maxm = 1e2; LL Mat[maxm+5][maxm+5]; int turn,n; void gcd(LL a,LL b,LL &d,LL &x,LL &y) { if(!b) d=a,x=1,y=0; else{ ++turn; gcd(b,a%b,d,y,x); y-=x*(a/b); } } LL det(LL n) { LL tmp1[maxm+5],tmp2[maxm+5]; LL ans=1; for(int i=1;i<=n;++i){ for(int j=i+1;j<=n;++j){ if(Mat[j][i]!=0){ LL A=Mat[i][i],B=Mat[j][i],d,x,y; turn=0; gcd(A,B,d,x,y); for(int k=1;k<=n;++k) tmp1[k]=Mat[i][k],tmp2[k]=Mat[j][k]; for(int k=1;k<=n;++k) Mat[i][k]=(x*tmp1[k]+y*tmp2[k])%mod; A/=d,B/=d; if(turn&1) x=B,y=-A,ans=-ans%mod;else x=-B,y=A; for(int k=1;k<=n;++k) Mat[j][k]=(x*tmp1[k]+y*tmp2[k])%mod; } } ans=ans*Mat[i][i]%mod; } if(ans<0) ans+=mod; return ans; } int A[maxm], B[maxm]; int main(void) { Comb_init(); int nCase; scanf("%d", &nCase); while(nCase--){ int n, k; scanf("%d %d", &n, &k); for(int i=1; i<=k; i++) scanf("%d", &A[i]); for(int i=1; i<=k; i++) scanf("%d", &B[i]); for(int i=1; i<=k; i++){ for(int j=1; j<=k; j++){ int a, b; a = n-1+B[j]-A[i]; b = n-1; if(a < b) Mat[i][j] = 0; else if(a < 0 || b < 0) Mat[i][j] = 0; else Mat[i][j] = Comb(a, b); } } printf("%lld\n", det(k) % mod); } return 0; }