把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF348D Turtles

题面传送门
一看到两条路线不交我们就可以想到容斥。
两点间的路径条数显然可以\(O(n^2)\)递推出来。问题是怎么容斥。
考虑如果两条路线不交,那么一定一只乌龟开始第一步向上走,一只向右走。
同理,在终点时一定有一只乌龟最后一步向右走,另一只向上走。
所以变成了四个点之间的问题。
考虑如果\((1,2)\)点爬到\((n,m-1)\)点,那么一定会和另一只乌龟相交,所以一定不能考虑。
但是如果从\((1,2)\)点爬到\((n-1,m)\)点,我们就无法判断这些路径究竟有没有相交。
考虑相交的本质是两个起点同时到一个交点,然后由一个交点爬到两个终点,两个终点互换对于答案是没有影响的。
而一种情况是\((1,2)\)点爬到\((n,m-1)\)点,另一种就是从\((1,2)\)点爬到\((n-1,m)\)点中相交的部分。所以就可以容斥了。
代码实现:

#include<cstdio>
#define mod 1000000007
using namespace std;
int n,m,k,x,y,z,a[3039][3039];
long long f[3039][3039],ans;
char _s;
inline long long find(int x,int y,int l,int r){
	register int i,j;
	if(a[x][y])return 0;f[x][y]=1;
	for(i=x;i<=l;i++){
		for(j=y;j<=r;j++)if(!a[i][j])f[i][j]=(f[i][j]+f[i-1][j]+f[i][j-1])%mod; 
	}
	ans=f[l][r];
	for(i=x;i<=l;i++){
		for(j=y;j<=r;j++)f[i][j]=0;
	}
	return ans;
}
int main(){
	freopen("1.in","r",stdin);
	register int i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			_s=getchar();
			while(_s!='.'&&_s!='#') _s=getchar();
			a[i][j]=(_s=='.'?0:1);
		}
	}
	printf("%lld\n",(find(1,2,n-1,m)*find(2,1,n,m-1)%mod-find(1,2,n,m-1)*find(2,1,n-1,m)%mod+mod)%mod);
}
posted @ 2021-01-31 15:43  275307894a  阅读(42)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end