Description:
给定一个 n∗ m 的网格,你在左下角 (n,1),你只能往前走或者右拐,障碍和走过的点不能走。求走到 (y,x) 的方案数 mod k 的值。
n,m ≤ 100,k ≤ 10^9.
题解:
考虑当前走到了一个点,剩下的能走的范围是一个矩形。
于是倒着dp,设 表示当前剩余矩形的左上角右下角的坐标是(x1,y1)、(x2,y2),当前方向是p,注意一定在角上。
很容易想到枚举拐弯点来转移,复杂度 ,T飞了。
其实很多拐弯点的贡献和可以就是一个矩形的值,优化转移,复杂度
以矩形周长分层dp,滚动优化,空间即可优化下来。
初值就是重点在矩形角上且方向指向它。
Code:
#include<cstdio>
#include<cstring>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int N = 110;
char s[N][N];
int n, m, k, p, q;
int b1[N][N][N], b2[N][N][N];
int f[2][4][N][N][N], o;
int main() {
scanf("%d %d %d %d %d", &n, &m, &k, &q, &p);
fo(i, 1, n) scanf("%s", s[i] + 1);
fo(i, 1, n) fo(j, 1, m) if(s[i][j] == '*')
b1[i][j][j] = b2[j][i][i] = 1;
fo(i, 1, n) fo(len, 1, m - 1) fo(j, 1, m - len)
b1[i][j][j + len] = b1[i][j + 1][j + len] | b1[i][j][j + len - 1];
fo(i, 1, m) fo(len, 1, n - 1) fo(j, 1, n - len)
b2[i][j][j + len] = b2[i][j + 1][j + len] | b2[i][j][j + len - 1];
fo(ls, 0, n + m - 2) {
o = !o;
fo(x1, 1, p) {
fo(x2, max(x1, p), n) {
fo(y1, 1, min(m, q)) if(y1 <= q){
int y2 = y1 + ls - (x2 - x1); if(y2 < q || y2 > m) continue;
fo(t, 0, 3) {
f[o][t][x1][x2][y1] = 0;
if(x1 == p && y1 == q)
f[o][t][x1][x2][y1] |= (t == 3 && !b2[q][x1][x2]);
if(x1 == p && y2 == q)
f[o][t][x1][x2][y1] |= (t == 0 && !b1[p][y1][y2]);
if(x2 == p && y1 == q)
f[o][t][x1][x2][y1] |= (t == 2 && !b1[p][y1][y2]);
if(x2 == p && y2 == q)
f[o][t][x1][x2][y1] |= (t == 1 && !b2[q][x1][x2]);
if(t == 0) {
f[o][t][x1][x2][y1] += f[!o][t][x1][x2][y1];
if(!b1[x1][y1][y2]) f[o][t][x1][x2][y1] += f[!o][t + 1 & 3][x1 + 1][x2][y1];
} else
if(t == 1) {
f[o][t][x1][x2][y1] += f[!o][t][x1][x2 - 1][y1];
if(!b2[y2][x1][x2]) f[o][t][x1][x2][y1] += f[!o][t + 1 & 3][x1][x2][y1];
} else
if(t == 2) {
f[o][t][x1][x2][y1] += f[!o][t][x1][x2][y1 + 1];
if(!b1[x2][y1][y2]) f[o][t][x1][x2][y1] += f[!o][t + 1 & 3][x1][x2 - 1][y1];
} else
if(t == 3) {
f[o][t][x1][x2][y1] += f[!o][t][x1 + 1][x2][y1];
if(!b2[y1][x1][x2]) f[o][t][x1][x2][y1] += f[!o][t + 1 & 3][x1][x2][y1 + 1];
}
f[o][t][x1][x2][y1] %= k;
}
}
}
}
}
printf("%d\n", f[o][3][1][n][1]);
}