您的位置:首页 > 其它

校内互测 [from abclzr] T2 (DP)

2017-03-18 16:01 543 查看

题目描述

mrazer在一个 n 行 m列的棋盘上, 坐标(x,y)代表第 x 行第 y 列的棋盘格子。

他要从(1,1)走到(n,m),每次只能向右走一格或向下走一格,不能走出棋盘。而

且棋盘上有些格子是不能走的。mrazer 想要选择两条从(1,1)走到(n,m)的路,这

两条路上的格子除了(1,1)和(n,m)不能有重复的,也就是说两条路在中间不能有

交点。他想知道这两条路的选择一共有多少种不同的方案。两种选择中有一条路

不同则视这两种选择不同。

输入格式

从文件 in sun. 中读入数据。

第一行输入两个整数n ,m 。

接下来n 行,每行输入一个长度为m 的 01串,表示一个字符矩阵。

矩阵中第i 行第 j 个字符表示(i,j)这个格子的能不能走。字符’0’表示能走,字

符’1’表示不能走。

数据保证字符矩阵的(1,1)和(n,m)位置为’0’。

输出格式

输出到文件 out sun. 中

输出一个整数,表示不同的选择数。因为这个答案可能很大,所以请输出答

案对 1000000007取模的结果。

样例输入

3 3

000

010

000

样例输出

1

数据范围

n,m<=5000

题解

这道题暴力DP应该比较好写

f[i][j][k]表示第一条路径到(i,j),第二条路径到(k,i+j-k)的合法的方案数

但是n,m<=5000,所以需要对思路进行转换

我们定义有限集合:

X0:从(2,1)走到(n,m-1)的不走1路径集合。

X1:从(1,2)走到(n-1,m)的不走1路径集合。

X2:从(2,1)走到(n-1,m)的不走1路径集合。

X3:从(1,2)走到(n,m-1)的不走1路径集合。



答案就是:

|{(x0,x1)|x0∈X0,x1∈X1 x0,x1的路径不相交}|

利用容斥原理

|{(x0,x1)|x0∈X0,x1∈X1}|−|{(x0,x1)|x0∈X0,x1∈X1 x0,x1的路径相交}|

然后我们定义

A=|{(x0,x1)|x0∈X0,x1∈X1 x0,x1的路径相交}|

B=|{(x2,x3)|x2∈X2,x3∈X3|

对 A 中的一个二元组(x0,x1),找到x0和x1最后相交的点,把这个点之后的x0和x1的路径互换一下,就组成新的(x2,x3)

对于A,B中的点对是一一对应的,所以|A|=|B|

那么最后的答案就是

|X0||X1|−|X2||X3|

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 5003
#define p 1000000007
#define LL long long
using namespace std;
int n,m;
LL f[N][N],g[N][N];
char s[N][N];
int main()
{
freopen("sun.in","r",stdin);
freopen("sun.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%s",s[i]+1);
f[2][1]=g[1][2]=1;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (s[i][j]!='1') {
if (i!=2||j!=1) f[i][j]=(f[i-1][j]+f[i][j-1])%p;
if (i!=1||j!=2) g[i][j]=(g[i-1][j]+g[i][j-1])%p;
}
LL ans=f
[m-1]*g[n-1][m]%p-f[n-1][m]*g
[m-1]%p;
ans=(ans%p+p)%p;
printf("%I64d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp