【雅礼联考DAY02】Path

Description:

给定一个 n∗ m 的网格,你在左下角 (n,1),你只能往前走或者右拐,障碍和走过的点不能走。求走到 (y,x) 的方案数 mod k 的值。

n,m ≤ 100,k ≤ 10^9.

题解:

考虑当前走到了一个点,剩下的能走的范围是一个矩形。

于是倒着dp,设 f p , x 1 , y 1 , x 2 , y 2 表示当前剩余矩形的左上角右下角的坐标是(x1,y1)、(x2,y2),当前方向是p,注意一定在角上。

很容易想到枚举拐弯点来转移,复杂度 O ( n 5 ) ,T飞了。

其实很多拐弯点的贡献和可以就是一个矩形的值,优化转移,复杂度 O ( n 4 )

以矩形周长分层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]);
}

猜你喜欢

转载自blog.csdn.net/cold_chair/article/details/81047800