NOI2005瑰丽华尔兹-单调队列

/*
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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值