题目

题目链接:https://gmoj.net/senior/#main/show/1753
胖子很有钱。他购买了一个先进的跑步机(真的不一样哦~~~~)。
这个跑步机是这样的:

  1. 可以把它看成一个N*M的矩阵。有的格子是障碍不能经过(用x表示),有的格子是空地可以经过(用.表示)。
  2. 对于每一个时段,跑步机有不同的倾斜方向。由于胖子太胖了,所以他这个时候只有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;
}