【JZOJ1753】锻炼身体
题目
题目链接:https://gmoj.net/senior/#main/show/1753
胖子很有钱。他购买了一个先进的跑步机(真的不一样哦~~~~)。
这个跑步机是这样的:
- 可以把它看成一个N*M的矩阵。有的格子是障碍不能经过(用x表示),有的格子是空地可以经过(用.表示)。
- 对于每一个时段,跑步机有不同的倾斜方向。由于胖子太胖了,所以他这个时候只有2种选择:要么沿这个方向移动(每秒移动1个格子),或者艰难的保持在原来的位置不动。
现在胖子已经设定好了跑步机在不同时段中的倾斜方向。众所周知,保持在原地不动是不会做功的。胖子要减肥就要做功。所以他想知道他最多能够跑多长的路程。
思路
设 \(f[k][i][j]\) 表示第 \(k\) 个时段后在 \((i,j)\) 的最大路程。
假设第 \(k\) 个时刻是向上的,那么 \(f[k][i][j]\) 可能由 \(f[k-1][i\sim n][j]\) 转移而来。注意要判断不能走的格子和这个时刻的时间大小。
暴力搞是 \(O(kn^3)\) 的,发现一个点只可以由一段前面固定长度的区间最大值转移而来,直接上单调队列优化即可。
时间复杂度 \(O(kn^2)\)。
代码
#include <bits/stdc++.h>
#define Clear { while(q.size()) q.pop_back(); continue; }
using namespace std;
const int N=210,Inf=1e9;
int n,m,sx,sy,t,ans,f[N][N][N];
char ch[N][N];
deque<int> q;
struct node
{
int s,t,p;
}a[N];
bool cmp(node x,node y)
{
return x.s<y.s;
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&sx,&sy,&t);
for (int i=1;i<=n;i++)
scanf("%s",ch[i]+1);
for (int i=1;i<=t;i++)
scanf("%d%d%d",&a[i].s,&a[i].t,&a[i].p);
sort(a+1,a+1+t,cmp);
for (int i=2;i<=t;i++)
if (a[i].s!=a[i-1].t+1)
{
a[i].t-=(a[i].s-a[i-1].t-1);
a[i].s=a[i-1].t+1;
}
memset(f,0xcf,sizeof(f));
f[0][sx][sy]=0;
for (int k=1;k<=t;k++)
{
int tt=a[k].t-a[k].s+1;
if (a[k].p==1)
{
for (int j=1;j<=m;j++)
{
while (q.size()) q.pop_back();
for (int i=n;i>=1;i--)
{
if (ch[i][j]=='x') Clear;
while (q.size() && q.front()-i>tt) q.pop_front();
while (q.size() && f[k-1][q.back()][j]+q.back()<=f[k-1][i][j]+i)
q.pop_back();
q.push_back(i);
if (q.size()) f[k][i][j]=f[k-1][q.front()][j]+q.front()-i;
}
}
}
if (a[k].p==2)
{
for (int j=1;j<=m;j++)
{
while (q.size()) q.pop_back();
for (int i=1;i<=n;i++)
{
if (ch[i][j]=='x') Clear;
while (q.size() && i-q.front()>tt) q.pop_front();
while (q.size() && f[k-1][q.back()][j]-q.back()<=f[k-1][i][j]-i)
q.pop_back();
q.push_back(i);
if (q.size()) f[k][i][j]=f[k-1][q.front()][j]+i-q.front();
}
}
}
if (a[k].p==3)
{
for (int i=1;i<=n;i++)
{
while (q.size()) q.pop_back();
for (int j=m;j>=1;j--)
{
if (ch[i][j]=='x') Clear;
while (q.size() && q.front()-j>tt) q.pop_front();
while (q.size() && f[k-1][i][q.back()]+q.back()<=f[k-1][i][j]+j)
q.pop_back();
q.push_back(j);
if (q.size()) f[k][i][j]=f[k-1][i][q.front()]+q.front()-j;
}
}
}
if (a[k].p==4)
{
for (int i=1;i<=n;i++)
{
while (q.size()) q.pop_back();
for (int j=1;j<=m;j++)
{
if (ch[i][j]=='x') Clear;
while (q.size() && j-q.front()>tt) q.pop_front();
while (q.size() && f[k-1][i][q.back()]-q.back()<=f[k-1][i][j]-j)
q.pop_back();
q.push_back(j);
if (q.size()) f[k][i][j]=f[k-1][i][q.front()]+j-q.front();
}
}
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
ans=max(ans,f[t][i][j]);
printf("%d",ans);
return 0;
}