【[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;
}

猜你喜欢

转载自www.cnblogs.com/asuldb/p/10205725.html