[NOI2005]瑰丽华尔兹

用单调队列优化的dp

dp[i][j][k]表在第i段时间走到(j,k)的步数

正常转移是n^5

但可以发现一段时间走的方向一定所以可以用单调队列优化

时间复杂度n^3

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,stx,sty,k,l,r,ans;
int head,tail;
char mp[205][205];
int tim[205];
int dp[255][205][205];
int dx[5]={0,-1,1,0,0};
int dy[5]={0,0,0,-1,1};
struct node{
    int val;
    int pos;
    node(){}
    node(int val,int pos):val(val),pos(pos){}
}que[205];
void DP(int x,int y,int t){
    head=1,tail=0;
    for(int i=1;x>=1&&x<=n&&y>=1&&y<=m;i++,x+=dx[tim[t]],y+=dy[tim[t]]){
        if(mp[x][y]=='x'){
            head=1,tail=0;
            continue;
        }
        while(tail>=head&&dp[t-1][x][y]>que[tail].val+i-que[tail].pos)tail--;
        que[++tail]=node(dp[t-1][x][y],i);
        if(que[tail].pos-que[head].pos>r-l+1)head++;
        dp[t][x][y]=que[head].val+i-que[head].pos;
        ans=max(ans,dp[t][x][y]);
    }
}
int main(){ 
    scanf("%d%d%d%d%d",&n,&m,&stx,&sty,&k);
    for(int i=1;i<=n;i++){
        scanf("%s",mp[i]+1);
    }
    for(int i=0;i<=k;i++){
        for(int j=1;j<=n;j++){
            for(int z=1;z<=m;z++){
                dp[i][j][z]=-0x3f3f3f3f;
            }
        }
    }
    dp[0][stx][sty]=0;
    for(int i=1;i<=k;i++){
        scanf("%d%d%d",&l,&r,&tim[i]);
        if(tim[i]==1){
            for(int j=1;j<=m;j++){
                DP(n,j,i);
            }
        }
        if(tim[i]==2){
            for(int j=1;j<=m;j++){
                DP(1,j,i);
            }
        }
        if(tim[i]==3){
            for(int j=1;j<=n;j++){
                DP(j,m,i);
            }
        }
        if(tim[i]==4){
            for(int j=1;j<=n;j++){
                DP(j,1,i);
            }
        }
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/lnxcj/p/9808016.html