2018.09.10【NOI2005】瑰丽华尔兹(单调队列优化DP)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/82597627

传送门


解析:

f i , j , p 表示在第 p 个时间段后,停留在 ( i , j ) 时能够得到的最大滑行距离。
那么状态转移方程。我就不写了。。。代码里面很明白了。

而对于每一次更新,都是用的上一次的答案,所以按顺序更新可以直接省略第三维,节约空间。

而且每一次的更新也显然满足单调性。所以就直接上单调队列优化。

对于家具的位置,直接清空队列就行了,因为前后无法转移。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
#define st static
#define map Map 

inline
ll getint(){
    re ll num=0;
    re char c;
    re bool f=0;
    while(!isdigit(c=gc()))if(c=='-')f=1;
    while(isdigit(c))num=(num<<1)+(num<<3)+(c^48),c=gc();
    return f?-num:num;
}

inline
void outint(int a){
    st char ch[13];
    if(a==0)pc('0');
    if(a<0)pc('-'),a=-a;
    while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
    while(ch[0])pc(ch[ch[0]--]);
}

cs int INF=0x3f3f3f3f;

bool map[201][201];
int f[201][201];
int n,m,x,y,k;
int t[201],d[201];

int q[201],head,tail;
int num[201];

int main(){
    n=getint();
    m=getint();
    x=getint();
    y=getint();
    k=getint();
    memset(f,-INF,sizeof f);
    f[x][y]=0;
    for(int re i=1;i<=n;++i){
        string s;
        cin>>s;
        for(int re j=1;j<=m;++j)if(s[j-1]=='x')map[i][j]=1;
    }

    for(int re i=1;i<=k;++i){
        int a=getint(),b=getint();
        t[i]=b-a+1,d[i]=getint();
    }

    for(int re kk=1;kk<=k;++kk){
        switch(d[kk]){
            case 1:{
                for(int re j=1;j<=m;++j){
                    head=1;tail=0;
                    for(int re i=n;i>=1;--i){
                        if(map[i][j]){head=1;tail=0;continue;}
                        while(q[head]-i>t[kk]&&head<=tail)++head;
                        while((num[tail]<0||num[tail]+q[tail]-i<f[i][j])&&head<=tail)--tail;
                        q[++tail]=i;num[tail]=f[i][j];
                        f[i][j]=max(f[i][j],num[head]+q[head]-i);
                    }
                }
                break;
            }
            case 2:{
                for(int re j=1;j<=m;++j){
                    head=1;tail=0;
                    for(int re i=1;i<=n;++i){
                        if(map[i][j]){head=1;tail=0;continue;}
                        while(i-q[head]>t[kk]&&head<=tail)++head;
                        while((num[tail]<0||num[tail]-q[tail]+i<f[i][j])&&head<=tail)--tail;
                        q[++tail]=i;num[tail]=f[i][j];
                        f[i][j]=max(f[i][j],num[head]-q[head]+i);
                    }
                }
                break;
            }
            case 3:{
                for(int re i=1;i<=n;++i){
                    head=1;tail=0;
                    for(int re j=m;j>=1;--j){
                        if(map[i][j]){head=1;tail=0;continue;}
                        while(q[head]-j>t[kk]&&head<=tail)++head;
                        while((num[tail]<0||num[tail]+q[tail]-j<f[i][j])&&head<=tail)--tail;
                        q[++tail]=j;num[tail]=f[i][j];
                        f[i][j]=max(f[i][j],num[head]+q[head]-j);
                    }
                }
                break;
            }
            case 4:{
                for(int re i=1;i<=n;++i){
                    head=1;tail=0;
                    for(int re j=1;j<=m;++j){
                        if(map[i][j]){head=1;tail=0;continue;}
                        while(j-q[head]>t[kk]&&head<=tail)++head;
                        while((num[tail]<0||num[tail]-q[tail]+j<f[i][j])&&head<=tail)--tail;
                        q[++tail]=j;num[tail]=f[i][j];
                        f[i][j]=max(f[i][j],num[head]-q[head]+j);
                    }
                }
                break;
            }
        }
    }
    int ans=0;
    for(int re i=1;i<=n;++i)for(int re j=1;j<=m;++j)ans=max(ans,f[i][j]);
    outint(ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/82597627