1 条题解

  • 0
    @ 2026-9-26 20:16:52

    神仙题。对第一篇题解做出了一些补充说明并说了一下自己的理解。

    首先你考虑去刻画小偷走的过程,发现它必然是一个划分螺旋矩阵的过程,如图所示,借用了一下第一篇题解的图:

    其中红色的是你走的路线,黑色是你划分出来的矩阵,并且我们发现,你总按照上,右,下,左的循环去走。

    我们以此来考虑一个很神的 DP 状态,定义 fu,r,d,l,pf_{u,r,d,l,p} 表示你在矩形 (u,l,d,r)(u,l,d,r) 内,所有满足条件的路线数量,并且当前你沿着 pp 方向运动,u,r,d,lu,r,d,l 分别表示你当前在的这个矩形的上、右、左、下边界,pp 就是你行走的状态,00 表示在向上走,11 表示在向右走,以此类推。继续考虑转移,我们用小矩阵去更新大矩形,以当前正在向上为例,也就是我们要找到一个高度去右拐,此时最左边的一列已经访问过了,所以要 l+1l+1,于是如果不考虑障碍物,转移式为 fu,r,d,l,0=∑k=udfk,r,d,l+1,1f_{u,r,d,l,0}=\sum_{k=u}^d f_{k,r,d,l+1,1},解图大概是这样的(为 AI 大模型生成,仅供参考):

    此时考虑障碍物的问题,我们记路径上是否有警察即为 checkucheck_u,具体的,从当前位置走到转弯点的那条边上有没有障碍,维护是简单的随便前缀和可以求得,把 checkcheck 乘入 DP 转移即可。

    然后剩下的转移式类似去考虑即可,加入障碍物也是简单的。接着就是要去优化这个 DP 了,我们把求和式拆一下,还是以向上为例,那么就可以拆成 $f_{u,r,d,l+1,1}\times check_u+\sum_{k=u+1}^d (f_{u,r,d,l+1,1}\times check_k)$,后面那部分恰好是 fu+1,r,d,l+1,1f_{u+1,r,d,l+1,1},那么我们的转移就被优化到了 O(n4)O(n^4)。此时再去考虑空间我问题,你注意到每一个来源状态的矩形大小都减少了 11,也就是说当前层只依赖长度和宽度和少 11 的层,我们对长度和宽度的和做滚动数组即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=105;
    int n,m,mod;
    int x,y;
    int s1[N][N];
    int s2[N][N];
    int f[2][N][N][N][4];
    int main(){
        cin>>n>>m>>mod>>y>>x;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                char c;
                cin>>c;
                while(c!='+'&&c!='*')cin>>c;
                s1[i][j]=s1[i][j-1]+(c=='*');
                s2[i][j]=s2[i-1][j]+(c=='*');
            }
        }
        for(int s=2;s<=n+m;s++){
            int tmp=s&1;
            int last=tmp^1;
            for(int h=1;h<s;h++){
                int w=s-h;
                if(h>n||w>m)continue;
                for(int u=1;u+h-1<=n;u++){
                    int d=u+h-1;
                    for(int l=1;l+w-1<=m;l++){
                        int r=l+w-1;
                        if(d<x||r<y)continue;
                        f[tmp][u][l][d][0]=
                        (
                            f[last][u+1][l][d][0]
                            +
                            (s2[d][l]==s2[u-1][l])
                            *
                            (f[last][u][l+1][d][1]+(u==x&&l==y))
                        )%mod;
                        f[tmp][u][l][d][1]=
                        (
                            f[last][u][l][d][1]
                            +
                            (s1[u][r]==s1[u][l-1])
                            *
                            (f[last][u+1][l][d][2]+(u==x&&r==y))
                        )%mod;
                        f[tmp][u][l][d][2]=
                        (
                            f[last][u][l][d-1][2]
                            +
                            (s2[d][r]==s2[u-1][r])
                            *
                            (f[last][u][l][d][3]+(d==x&&r==y))
                        )%mod;
                        f[tmp][u][l][d][3]=
                        (
                            f[last][u][l+1][d][3]
                            +
                            (s1[d][r]==s1[d][l-1])
                            *
                            (f[last][u][l][d-1][0]+(d==x&&l==y))
                        )%mod;
                    }
                }
            }
        }
        cout<<f[(n+m)&1][1][1][n][0];
    }
    
    • 1

    信息

    ID
    2779
    时间
    14000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    5
    已通过
    5
    上传者