JZOJ4019. 【雅礼联考DAY02】Path

本文介绍了一种在给定网格中计算从特定起点到终点的不同路径数量的方法。考虑到障碍物和路径约束,采用动态规划技术优化计算过程。文章详细解释了如何通过枚举行列总和并使用滑动窗口技术来降低算法的空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

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

数据范围

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

Analysis

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

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值