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

猜你喜欢

转载自www.cnblogs.com/lokiii/p/9614852.html
今日推荐