题目大意:给你一个n*m棋盘(n,m<=200),有一个人从给定的点s,e出发,有一些坏点不能走,一共给定k段连续的时间(k<=200),在某一段时间之内它只能向一个给定的方向移动,在某一时刻,它可以移动或者不移动。求碰到坏点之前/总时间结束时,最长移动的距离。
朴素DP的方法是: 表示在时间点t时,在位置(i,j)时已经走过的最长距离,i' j'表示这一步移动前的位置
得到方程
空间时间都会炸
那么重新定义 表示在第k个时间段,在位置(i,j)时已经走过的最长距离
那么显然,注意要根据移动的方向决定枚举的顺序
由于dis在同一行/列具有单调性,用队列随便优化一下就行了,如果dis大于t[i]-s[i]就删除队首,如果碰到障碍就清队列
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 52
using namespace std;
int n,m,sx,sy,K,now,pst;
int mp[N][N],st[N],ed[N],dir[N],que[N];
int xx[]={0,-1,1,0,0},yy[]={0,0,0,-1,1};
char str[N][N];
int f[2][N][N];
void upd1(int k)
{
int hd,tl;
for(int j=1;j<=m;j++)
{
hd=1,tl=0;
for(int i=n;i>=1;i--)
{
if(mp[i][j]) {hd=1,tl=0;continue;}
while(hd<=tl&&f[pst][que[tl]][j]+que[tl]-i<=f[pst][i][j])
tl--;
que[++tl]=i;
while(hd<=tl&&que[hd]-i>ed[k]-st[k]+1)
hd++;
f[now][i][j]=f[pst][que[hd]][j]+que[hd]-i;
}
}
}
void upd2(int k)
{
int hd,tl;
for(int j=1;j<=m;j++)
{
hd=1,tl=0;
for(int i=1;i<=n;i++)
{
if(mp[i][j]) {hd=1,tl=0;continue;}
while(hd<=tl&&f[pst][que[tl]][j]+i-que[tl]<=f[pst][i][j])
tl--;
que[++tl]=i;
while(hd<=tl&&i-que[hd]>ed[k]-st[k]+1)
hd++;
f[now][i][j]=f[pst][que[hd]][j]+i-que[hd];
}
}
}
void upd3(int k)
{
int hd,tl;
for(int i=1;i<=n;i++)
{
hd=1,tl=0;
for(int j=m;j>=1;j--)
{
if(mp[i][j]) {hd=1,tl=0;continue;}
while(hd<=tl&&f[pst][i][que[tl]]+que[tl]-j<=f[pst][i][j])
tl--;
que[++tl]=j;
while(hd<=tl&&que[hd]-j>ed[k]-st[k]+1)
hd++;
f[now][i][j]=f[pst][i][que[hd]]+que[hd]-j;
}
}
}
void upd4(int k)
{
int hd,tl;
for(int i=1;i<=n;i++)
{
hd=1,tl=0;
for(int j=1;j<=m;j++)
{
if(mp[i][j]) {hd=1,tl=0;continue;}
while(hd<=tl&&f[pst][i][que[tl]]+j-que[tl]<=f[pst][i][j])
tl--;
que[++tl]=j;
while(hd<=tl&&j-que[hd]>ed[k]-st[k]+1)
hd++;
f[now][i][j]=f[pst][i][que[hd]]+j-que[hd];
}
}
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&sx,&sy,&K);
for(int i=1;i<=n;i++){
scanf("%s",str[i]+1);
for(int j=1;j<=m;j++)
if(str[i][j]=='x')
mp[i][j]=1;
}
for(int i=1;i<=K;i++)
scanf("%d%d%d",&st[i],&ed[i],&dir[i]);
memset(f,-0x3f,sizeof(f));
f[0][sx][sy]=0;
now=1,pst=0;
for(int k=1;k<=K;k++)
{
if(dir[k]==1) upd1(k);
if(dir[k]==2) upd2(k);
if(dir[k]==3) upd3(k);
if(dir[k]==4) upd4(k);
swap(now,pst);
}
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
ans=max(f[pst][i][j],ans);
printf("%d\n",ans);
return 0;
}