JZOJ4019. 【雅礼联考DAY02】Path

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/XLno_name/article/details/81047987

题意

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

数据范围

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

Analysis

首先一眼非常不可做,我们画图看看,发现它走的路线一定是圈套圈。类似于层层矩形相嵌。此时有想法了,我们考虑对矩形 D P 。设 f p , i , j , k , l ,表示当前方向为 p ,矩形左上角为 i , j ,右下角为 k , l 的方案。
在拐点统计方案,考虑倒着从终点开始做。但是直接统计是 O ( n 5 ) 的,需要在拐点枚举走多少步。考虑每一次拐前的矩形,发现每一次都是少一列,或少一行的矩形。那我们可以考虑矩形构建组合起来。例如 f 0 , i , j , k , l = f 0 , i , j , k , l 1 + f 1 , i + 1 , j , k , l ,考虑路线组合前矩形的形状。但是空间复杂度爆炸了。
由于每一次矩形行列总和加 1 。所以我们可以枚举行列总和,然后滑动数组优化空间,就可以通过这道题目。 P . S D P 的初值有点奇妙,不能直接赋值,只有刚好从起点走了一个方向才能赋 1

Code

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 100 + 5;
char s[N][N];
int f[2][N][N][N][4],h[N][N],li[N][N];
int n,m,x,y,K;
int main()
{
    scanf("%d%d%d",&n,&m,&K);
    scanf("%d%d",&x,&y); swap(x,y);
    for (int i = 1 ; i <= n ; ++i)
        for (int j = 1 ; j <= m ; ++j) scanf(" %c",&s[i][j]);
    for (int i = 1 ; i <= n ; ++i)
        for (int j = 1 ; j <= m ; ++j)
        {
            h[i][j] = h[i - 1][j] + (s[i][j] == '*');
            li[i][j] = li[i][j - 1] + (s[i][j] == '*');
        }
    for (int i = 0 ; i <= n + m - 2 ; ++i)
        for (int j = y ; j >= 1 && y - j <= i ; --j)
            for (int l = y ; l <= m && l - j <= i ; ++l)
                for (int k = x ; k <= n ; ++k)
                {
                    int d = k + l - i - j,s = i & 1,nx = s ^ 1;
                    if (d > x || d < 0) continue;
                    f[s][j][k][l][0] = (l > y) * f[nx][j][k][l - 1][0] + (li[d][j - 1] == li[d][l] && d < x) * f[nx][j][k][l][1];
                    f[s][j][k][l][1] = (k > x) * f[nx][j][k - 1][l][1] + (h[d - 1][l] == h[k][l] && l > y) * f[nx][j][k][l - 1][2];
                    f[s][j][k][l][2] = (j < y) * f[nx][j + 1][k][l][2] + (li[k][j - 1] == li[k][l] && k > x) * f[nx][j][k - 1][l][3];
                    f[s][j][k][l][3] = (d < x) * f[nx][j][k][l][3] + (h[d - 1][j] == h[k][j] && j < y) * f[nx][j + 1][k][l][0];
                    f[s][j][k][l][0] += (d == x && l == y && li[d][j - 1] == li[d][l]);
                    f[s][j][k][l][1] += (k == x && l == y && h[d - 1][l] == h[k][l]);
                    f[s][j][k][l][2] += (k == x && j == y && li[k][j - 1] == li[k][l]);
                    f[s][j][k][l][3] += (d == x && j == y && h[d - 1][j] == h[k][j]);
                    for (int now = 0 ; now < 4 ; ++now) f[s][j][k][l][now] %= K;
                }
    printf("%d\n",f[(n + m - 2) & 1][1][n][m][3]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/XLno_name/article/details/81047987