/*
NOI2005瑰丽华尔兹
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1499
题解:单调队列
(1)朴素的DP:
for (1~k)//k个时间区间 *200
for (1~n,1~m) n*m个点 *200*200
for (1~时间区间长度) *200
超时~
(2)利用决策的单调性,减少1个维度,详见代码
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int NN=202;
int n,m,flag;
char c[NN][NN];
int dp[2][NN][NN];
int q[NN],f,r;
void up(int l)
{
for (int j=1; j<=m; j++)
{
f=0; r=-1;
for (int i=n; i; i--)
{
dp[flag][i][j]=dp[flag^1][i][j];
if (c[i][j]=='x') { f=0; r=-1; continue; }
if (dp[flag^1][i][j]!=-1)
{
while (f<=r && dp[flag^1][q[r]][j]+q[r]<=dp[flag^1][i][j]+i) r--;
q[++r]=i;
}
while (f<=r && q[f]-i>l) f++;
if (f<=r)
dp[flag][i][j]=max(dp[flag][i][j],dp[flag^1][q[f]][j]+q[f]-i);
}
}
}
void down(int l)
{
for (int j=1; j<=m; j++)
{
f=0; r=-1;
for (int i=1; i<=n; i++)
{
dp[flag][i][j]=dp[flag^1][i][j];
if (c[i][j]=='x') { f=0; r=-1; continue; }
if (dp[flag^1][i][j]!=-1)
{
while (f<=r && dp[flag^1][q[r]][j]-q[r]<=dp[flag^1][i][j]-i) r--;
q[++r]=i;
}
while (f<=r && i-q[f]>l) f++;
if (f<=r) dp[flag][i][j]=max(dp[flag][i][j],dp[flag^1][q[f]][j]+i-q[f]);
}
}
}
void left(int l)
{
for (int i=1; i<=n; i++)
{
f=0; r=-1;
for (int j=m; j; j--)
{
dp[flag][i][j]=dp[flag^1][i][j];
if (c[i][j]=='x') { f=0; r=-1; continue; }
if (dp[flag^1][i][j]!=-1)
{
while (f<=r && dp[flag^1][i][q[r]]+q[r]<=dp[flag^1][i][j]+j) r--;
q[++r]=j;
}
while (f<=r && q[f]-j>l) f++;
if (f<=r) dp[flag][i][j]=max(dp[flag][i][j],dp[flag^1][i][q[f]]+q[f]-j);
}
}
}
void right(int l)
{
for (int i=1; i<=n; i++)
{
f=0; r=-1;
for (int j=1; j<=m; j++)
{
dp[flag][i][j]=dp[flag^1][i][j];
if (c[i][j]=='x') { f=0;r=-1; continue; }
if (dp[flag^1][i][j]!=-1)
{
while (f<=r && dp[flag^1][i][q[r]]-q[r]<=dp[flag^1][i][j]-j) r--;
q[++r]=j;
}
while (f<=r && j-q[f]>l) f++;
if (f<=r) dp[flag][i][j]=max(dp[flag][i][j],dp[flag^1][i][q[f]]+j-q[f]);
}
}
}
int main()
{
int x,y,k,a,b,d;
int ch;
scanf("%d%d%d%d%d",&n,&m,&x,&y,&k);
for (int i=1; i<=n; i++)
{
for (int j=1; j<=m; j++)
{
ch=getchar();
while (ch!='.' && ch!='x') ch=getchar();
c[i][j]=ch;
dp[0][i][j]=-1;
}
}
dp[0][x][y]=0;
flag=0;
while (k--)
{
flag=1-flag;
scanf("%d%d%d",&a,&b,&d);
a=b-a+1;
switch (d)
{
case 1:up(a); break;
case 2:down(a); break;
case 3:left(a); break;
case 4:right(a); break;
}
}
int ans=0;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
{
if (dp[flag][i][j]>ans) ans=dp[flag][i][j];
}
printf("%d\n",ans);
return 0;
}
NOI2005瑰丽华尔兹-单调队列
最新推荐文章于 2017-10-29 11:02:16 发布