1008考试T3
1008考试T3
题目大意:
给定一张𝑛×𝑚的网格图,A想从(1,1)走到(1,𝑚),B想从(𝑛,1)走到(𝑛,𝑚)。二者都只能向右或是向上下移动,网格图有障碍不能经过,一个空地若被其中一人经过就不能被另一人经过。求方案数对1000000007取模的结果。"."表示空地,"#"表示障碍。对于100%的数据,1≤𝑛,𝑚≤300。
显然DP。应该算线性DP吧。
考场上不会做,打了个20分的缩索。
\(f[i][j][k]\)表示当前在第\(i\)列,\(A\)在\((j, i)\), \(B\)在\((k, i)\),两人不相交路径的方案数。
那么转移很简单:\(f[i][j][k] = \displaystyle \sum_{p} \sum_{q} f[i - 1][p][q]\)。\(p, q\)是可以到达\(j, k\)的点,也就是说它们之间没有障碍物。显然第一维可以去掉。
\(up[i][j], down[i][j]\)分别表示点\((i, j)\)往上走/往下走可以到达哪一行,中间没有障碍物。
不过这么做是\(O(n^5)\)的做法,过不了,我们可以用前缀和优化一下。
\(g[i][j]\)表示\(f[i][j]\)的一维前缀和,\(h[i][j]\)表示二维前缀和。复杂度\(O(n ^ 3)\)。
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 305, mod = 1000000007;
int n, m, ans;
int up[N][N], down[N][N], f[N][N], g[N][N], h[N][N];
char ch[N][N];
void make_prefix() {
for(int i = 1;i <= n; i++)
for(int j = 1;j <= n; j++) g[i][j] = (g[i - 1][j] + f[i][j]) % mod;
for(int i = 1;i <= n; i++)
for(int j = 1;j <= n; j++) h[i][j] = (h[i][j - 1] + g[i][j]) % mod;
}
int query(int x, int l, int r) { return (g[r][x] - g[l - 1][x] + mod) % mod; }
int query(int x, int xx, int y, int yy) { return (((h[xx][yy] + h[x - 1][y - 1]) % mod - (h[xx][y - 1] + h[x - 1][yy]) % mod) + mod) % mod; }
int main() {
n = read(); m = read();
for(int i = 1;i <= n; i++) cin >> (ch[i] + 1);
for(int j = 1;j <= m; j++) {
up[0][j] = 0;
for(int i = 1;i <= n; i++) up[i][j] = ch[i][j] == '#' ? i : up[i - 1][j];
down[n + 1][j] = n + 1;
for(int i = n;i >= 1; i--) down[i][j] = ch[i][j] == '#' ? i : down[i + 1][j];
}
f[1][n] = 1; make_prefix();
for(int i = 1;i <= m; i++) {
memset(f, 0, sizeof(f));
for(int j = 1;j <= n; j++) {
if(ch[j][i] == '#' || ch[j][i + 1] == '#') continue;
int tmp = 0, l = up[j][i] + 1, r = down[j][i] - 1;
for(int k = j + 1;k <= n; k++) {
if(ch[k][i] == '#') { tmp = 0; continue; }
tmp = (tmp + query(k, l, min(r, k - 1))) % mod;
if(ch[k][i + 1] != '#') f[j][k] = (tmp + query(l, min(r, k - 1), k + 1, down[k][i] - 1)) % mod;
}
}
make_prefix();
}
printf("%d", f[1][n]);
return 0;
}