题目分析
首先,同一根对角线上的行为决策必须一样(要么都往右要么都往下)。

行走是循环的,走到最右就变成最左,走到最左就变成最右了,所以“一根对角线”的意义也是循环的,比如说下图每一种颜色的点都属于同一根对角线。

假设有一根对角线,对于它上面的每一个点(x,y)(x,y)(x,y),x+y=kx+y=kx+y=k。当(x,y)(x,y)(x,y)出了边界后,为了使它拥有合法的意义,需要(x+=nx+=nx+=n或x−=nx-=nx−=n或y+=my+=my+=m或y−=my-=my−=m),不难发现,最后所有满足x+y=k+an+bmx+y=k+an+bmx+y=k+an+bm(a,ba,ba,b为整数)的点都在这根对角线上。根据裴蜀定理,设d=gcd(n,m)d=gcd(n,m)d=gcd(n,m),所有满足x+y=k+tdx+y=k+tdx+y=k+td(ddd为整数)的点都在这根对角线上。因此,一共有ddd条不同的对角线。
而机器人每走一步,都一定会到达一根新的对角线,所以机器人的行走决策,存在长度为ddd的循环节。
假设对于每个ddd循环节,选择“向下走”走了dxdxdx步,“向右走”走了dydydy步。显然要gcd(dx,n)=1gcd(dx,n)=1gcd(dx,n)=1,才能到达每一行。要gcd(dy,m)=1gcd(dy,m)=1gcd(dy,m)=1,才能到达每一列。至于充分性……呃,意会(捂脸)……
枚举dxdxdx,dydydy也已知了,接下来的任务就只有确定循环内的决策了。
假设钦定机器人是在第PPP步决策撞到障碍的,假设我钦定了前PPP步决策是向下走xxx步,向右走yyy步,那么它撞到的障碍物的坐标应该被写成(1+x+k×dx,1+y+k×dy)(1+x+k \times dx,1+y+k \times dy)(1+x+k×dx,1+y+k×dy)的形式,且kkk要尽可能小。于是,设(1+x,1+y)(1+x,1+y)(1+x,1+y)点的“权值”为x+y+k×dx+y+k \times dx+y+k×d,即钦定在这步决策导致撞障碍物情况下,最早撞障碍物的时间。
接下来开始DP决策,设f(i,j,k)f(i,j,k)f(i,j,k)表示从(1,1)(1,1)(1,1)走到(i,j)(i,j)(i,j)这个点(即钦定走了i−1i-1i−1步向下,j−1j-1j−1步向右),走到的最小权值为kkk(即已经钦定好了的决策导致最早的撞墙时间)的方案数。DP转移就是选择向下还是向右,最后将所有的k×f(dx+1,dy+1,k)k \times f(dx+1,dy+1,k)k×f(dx+1,dy+1,k)加入答案中。
复杂度分析:k≤n∗mk \leq n*mk≤n∗m,DP复杂度O(n4)O(n^4)O(n4),枚举dxdxdx复杂度O(n)O(n)O(n),计算权值复杂度O(n4)O(n^4)O(n4),总复杂度O(n5)O(n^5)O(n5)。
代码
#include<bits/stdc++.h>
using namespace std;
#define RI register int
const int mod=998244353;
int T,n,m,d,ans,f[52][52][2502],val[52][52];
char mp[52][52];
int qm(int x) {return x>=mod?x-mod:x;}
int gcd(int x,int y) {return y?gcd(y,x%y):x;}
int DP(int dx,int dy) {
for(RI i=1;i<=dx+1;++i)
for(RI j=1;j<=dy+1;++j)
for(RI k=1;k<=n*m;++k) f[i][j][k]=0;
f[1][1][val[1][1]]=1;
for(RI i=1;i<=dx+1;++i)
for(RI j=1;j<=dy+1;++j)
for(RI k=1;k<=n*m;++k) {
if(!f[i][j][k]) continue;
if(i<=dx) f[i+1][j][min(k,val[i+1][j])]=
qm(f[i+1][j][min(k,val[i+1][j])]+f[i][j][k]);
if(j<=dy) f[i][j+1][min(k,val[i][j+1])]=
qm(f[i][j+1][min(k,val[i][j+1])]+f[i][j][k]);
}
int re=0;
for(RI i=1;i<=n*m;++i) re=qm(re+1LL*i*f[dx+1][dy+1][i]%mod);
return re;
}
int main()
{
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m),d=gcd(n,m),ans=0;
for(RI i=1;i<=n;++i) scanf("%s",mp[i]+1);
for(RI dx=1;dx<=d;++dx) {
if(gcd(dx,n)!=1||gcd(d-dx,m)!=1) continue;
for(RI x=1;x<=dx+1;++x)
for(RI y=1;y<=d-dx+1;++y) {
int tx=x,ty=y,nowd=x-1+y-1;val[x][y]=n*m;
do {
if(mp[tx][ty]=='1') {val[x][y]=nowd;break;}
tx+=dx,ty+=d-dx,nowd+=d;
if(tx>n) tx-=n; if(ty>m) ty-=m;
}while(tx!=x||ty!=y);
}
ans=qm(ans+DP(dx,d-dx));
}
printf("%d\n",ans);
}
return 0;
}
机器人行走问题的DP决策分析
博客围绕机器人行走问题展开分析。指出同一对角线行为决策须一致,行走有循环性,存在长度为d(d=gcd(n,m))的循环节。要到达每行每列需满足gcd(dx,n)=1和gcd(dy,m)=1。通过枚举dx确定dy,再确定循环内决策,最后进行DP决策,分析了复杂度为O(n5)。
930

被折叠的 条评论
为什么被折叠?



