CF348D LGV定理

考试考到这个了,本来考虑了容斥,爆炸欧鸡上面有一道叫 两双手 的类似的题,然后打了打发现貌似不好做,然后就开爆搜了qwq,现在恶补一下。

我们发现有一种东西叫做\(Lindström–Gessel–Viennot lemma\),上网搜一下,你就会发现你看不懂

这个定理就是求一个点集到另一点集的不相交路径,定理本质也还是容斥

这道题给你一个n*m的矩阵\((1\sim n, 1\sim m)\),现在有两只乌龟都从左上角(1,1)出发,到达右下角(n,m),乌龟每次只能往右或者往下走一格,且两只乌龟走的路径不能交叉,问一共有多少种走法。

首先显然可知的是一只乌龟必然从(1,2)走到(n-1, m),另一只必然从(2,1)走到(n,m-1),因为不能相交,

(有点像卡特兰数在坐标系中的意义)

根据定理,相当于求一个\(2*2\)行列式的值(都会吧qwq)

\[\left|\begin{array}{cccc} f_1 & f_2 \\ f_3 & f_4\\ \end{array}\right| \\ 其中 f_1=(2,1)->(n,m-1)的方案数\\ f_2=(2,1)->(n-1,m)的方案数\\ f_3=(1,2)->(n,m-1)的方案数\\ f_4=(1,2)->(n-1,m)的方案数\\ \]

两遍dp分别可以求出四个方案,代入行列式中,就可以求出(2,1)到(n,m-1),(1,2)到(n-1,m)且路径不相交的方案数了,\(ans=(f_1*f_4)-(f_2*f_3)\)

注意,记得取模qwq,允许的情况下,多取模一定没坏处qwq
代码锅了咕咕咕 一会补上

#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 3005
#define int long long
using namespace std;
const int mod = 1e9 + 7;
int n,m,az[maxn][maxn];
char a[maxn][maxn];
inline int add(int x,int y){if(x+y < 0) return x+y+mod;return x+y >= mod ? x+y-mod : x+y;}
int mul(int x, int y) {return 1ll * x * y % mod;}
inline void init(){
	scanf("%lld%lld",&n,&m);
	for(int i = 1;i <= n;i++)
		for(int j = 1;j <= m;j++)
			cin >> a[i][j];
}
inline int f(int x1,int y1,int x2,int y2){
	memset(az,0,sizeof(az));
	 for(int i = x1;i <= x2;i++) 
        for(int j = y1;j <= y2;j++) 
            if(a[i][j] == '0') {
                if(i == x1 && j == y1) az[i][j] = 1;
                else  az[i][j] = add(az[i - 1][j],az[i][j - 1]);              
            }
    return az[x2][y2];
}
signed main(){
	init();
	int ans=add(mul(f(1,2,n-1,m),f(2,1,n,m-1)),-mul(f(1,2,n,m-1),f(2,1,n-1,m)));
	printf("%lld",ans);
}

交学长的数据A了,在CF上过了样例但是WA了,咕咕咕

posted @ 2020-07-16 13:41  INFP  阅读(136)  评论(1编辑  收藏  举报