bzoj 1499: [NOI2005]瑰丽华尔兹【dp+单调队列】

设f[a][i][j]为第a段时间结束时在(i,j)位置的最长滑行距离,转移很好想,就是分四个方向讨论,然后枚举这段时间的滑行长度取个max即可
但是这样是O(n^4)的,考虑优化
发现同一行或列,取max对应a-1中的是单调挪动的一个区间,所以用单调栈维护当前区间,每次移动的时候要把左端点已经大于最长滑行距离的出队,然后把新点放进去,然后直接更新答案,这样就省去了一个n的时间
注意如果遇到障碍的话,当前的f赋值-inf,然后把队列清空

#include<iostream>
#include<cstdio>
using namespace std;
const int N=205,dx[]={0,-1,1,0,0},dy[]={0,0,0,-1,1},inf=1e9;
int n,m,k,sx,sy,s[N],t[N],d[N],f[N][N][N],q[N],l,r,ans;
char c[N][N];
int main()
{
	scanf("%d%d%d%d%d",&n,&m,&sx,&sy,&k);
	for(int i=1;i<=n;i++)
		scanf("%s",c[i]+1);
	for(int i=1;i<=k;i++)
		scanf("%d%d%d",&s[i],&t[i],&d[i]);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			f[0][i][j]=-inf;
	f[0][sx][sy]=0;
	for(int a=1;a<=k;a++)
	{
		if(d[a]==1)
		{
			for(int j=1;j<=m;j++)
			{
				l=1,r=0;
				for(int i=n;i>=1;i--)
				{
					if(c[i][j]=='x')
					{
						l=1,r=0;
						f[a][i][j]=-inf;
						continue;
					}
					while(l<=r&&q[l]-i>t[a]-s[a]+1)
						l++;
					while(l<=r&&f[a-1][i][j]+i>f[a-1][q[r]][j]+q[r])
						r--;
					q[++r]=i;
					f[a][i][j]=f[a-1][q[l]][j]+q[l]-i;
				}
			}
		}
		if(d[a]==2)
		{
			for(int j=1;j<=m;j++)
			{
				l=1,r=0;
				for(int i=1;i<=n;i++)
				{
					if(c[i][j]=='x')
					{
						l=1,r=0;
						f[a][i][j]=-inf;
						continue;
					}
					while(l<=r&&i-q[l]>t[a]-s[a]+1)
						l++;
					while(l<=r&&f[a-1][i][j]-i>f[a-1][q[r]][j]-q[r])
						r--;
					q[++r]=i;
					f[a][i][j]=f[a-1][q[l]][j]+i-q[l];
				}
			}
		}
		if(d[a]==3)
		{
			for(int i=1;i<=n;i++)
			{
				l=1,r=0;
				for(int j=m;j>=1;j--)
				{
					if(c[i][j]=='x')
					{
						l=1,r=0;
						f[a][i][j]=-inf;
						continue;
					}
					while(l<=r&&q[l]-j>t[a]-s[a]+1)
						l++;
					while(l<=r&&f[a-1][i][j]+j>f[a-1][i][q[r]]+q[r])
						r--;
					q[++r]=j;//cerr<<i<<" "<<j<<" "<<q[l]<<"   "<<f[a-1][i][j]+j<<" "<<f[a-1][i][q[l]]+q[l]<<endl;
					f[a][i][j]=f[a-1][i][q[l]]+q[l]-j;
				}
			}
		}
		if(d[a]==4)
		{
			for(int i=1;i<=n;i++)
			{
				l=1,r=0;
				for(int j=1;j<=m;j++)
				{
					if(c[i][j]=='x')
					{
						l=1,r=0;
						f[a][i][j]=-inf;
						continue;
					}
					while(l<=r&&j-q[l]>t[a]-s[a]+1)
						l++;
					while(l<=r&&f[a-1][i][j]-j>f[a-1][i][q[r]]-q[r])
						r--;
					q[++r]=j;//cerr<<i<<" "<<j<<" "<<q[l]<<endl;
					f[a][i][j]=f[a-1][i][q[l]]+j-q[l];
				}
			}
		}
		// for(int i=1;i<=n;i++)
		// {
			// for(int j=1;j<=m;j++)
				// cerr<<f[a][i][j]<<" ";
			// cerr<<endl;
		// }
		// cerr<<endl;
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			ans=max(ans,f[k][i][j]);
	printf("%d\n",ans);
	return 0;
}
/*
10 10 5 8 5
..........
......xxxx
.....xxxxx
.....xxxxx
..........
xxxx......
..........
..........
..........
..x.......
1 5 3
6 7 1
8 11 2
12 15 3
16 17 2
*/
posted @ 2018-09-09 20:09  lokiii  阅读(150)  评论(0编辑  收藏  举报