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);
}