【[NOI2005]瑰丽华尔兹】

非常无脑和码农的单调队列优化(dp)

我们发现一个时间段内移动的情况是一样的,而时间段的数目又非常少,所以可以直接按照时间段来进行(dp)

由于每一次(dp)的移动距离都是小于等于某一个固定值的,于是可以直接上单调队列优化

复杂度(O(nmk))

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 205
#define max(a,b) ((a)>(b)?(a):(b))
int dp[maxn][maxn],now[maxn][maxn];
int n,m,sx,sy,K;
int S,E,wind;
char map[maxn][maxn];
int h,t,q[maxn];
inline int read()
{
	char c=getchar();
	int x=0;
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9')
		x=(x<<3)+(x<<1)+c-48,c=getchar();
	return x;
}
int main()
{
	n=read(),m=read(),sx=read(),sy=read(),K=read();
	for(re int i=1;i<=n;i++) scanf("%s",map[i]+1);
	memset(dp,-20,sizeof(dp)),memset(now,-20,sizeof(now));
	now[sx][sy]=dp[sx][sy]=0;
	for(re int O=1;O<=K;O++)
	{
		S=read(),E=read(),wind=read();
		int T=E-S+1;
		memset(now,-20,sizeof(now));
		if(wind==4)
		{
			for(re int i=1;i<=n;i++)
			{
				h=1,t=0;
				memset(q,0,sizeof(q));
				for(re int j=2;j<=m;j++)
				{
					while(h<=t&&dp[i][q[t]]-q[t]<dp[i][j-1]-j+1) t--;
					q[++t]=j-1;
					if(map[i][j-1]=='x') while(h<=t) h++;
					if(map[i][j]=='x') continue;
					while(h<=t&&q[h]+T<j) h++;
					if(h<=t) now[i][j]=max(dp[i][j],j+dp[i][q[h]]-q[h]);
				}
			}
		}
		if(wind==3)
		{
			for(re int i=1;i<=n;i++)
			{
				h=1,t=0;
				memset(q,0,sizeof(q));
				for(re int j=m-1;j>=1;j--)
				{
					while(h<=t&&dp[i][q[t]]+q[t]<dp[i][j+1]+j+1) t--;
					q[++t]=j+1;
					if(map[i][j+1]=='x') while(h<=t) h++;
					if(map[i][j]=='x') continue;
					while(h<=t&&j+T<q[h]) h++;
					if(h<=t) now[i][j]=max(dp[i][j],dp[i][q[h]]+q[h]-j);
				}
			}
		}
		if(wind==2)
		{
			for(re int j=1;j<=m;j++)
			{
				h=1,t=0;
				memset(q,0,sizeof(q));
				for(re int i=2;i<=n;i++)
				{
					while(h<=t&&dp[q[t]][j]-q[t]<dp[i-1][j]-i+1) t--;
					q[++t]=i-1;
					if(map[i-1][j]=='x') while(h<=t) h++;
					if(map[i][j]=='x') continue;
					while(h<=t&&q[h]+T<i) h++;
					if(h<=t) now[i][j]=max(dp[i][j],i+dp[q[h]][j]-q[h]);
				}
			}
		}
		if(wind==1)
		{
			for(re int j=1;j<=m;j++)
			{
				h=1,t=0;
				for(re int i=n-1;i>=1;i--)
				{
					while(h<=t&&dp[q[t]][j]+q[t]<dp[i+1][j]+i+1) t--;
					q[++t]=i+1;
					if(map[i+1][j]=='x') while(h<=t) h++;
					if(map[i][j]=='x') continue;
					while(h<=t&&i+T<q[h]) h++;
					if(h<=t) now[i][j]=max(dp[i][j],dp[q[h]][j]+q[h]-i);
				}
			}
		}
		for(re int i=1;i<=n;i++)
			for(re int j=1;j<=m;j++)
				dp[i][j]=max(dp[i][j],now[i][j]);
	}
	int ans=0;
	for(re int i=1;i<=n;i++)
		for(re int j=1;j<=m;j++)
			ans=max(ans,dp[i][j]);
	std::cout<<ans;
	return 0;
}
原文地址:https://www.cnblogs.com/asuldb/p/10205725.html