洛谷 P2254 [NOI2005] 瑰丽华尔兹(单调队列优化dp)

传送门


解题思路

对每一段时间进行操作,dp[i][j][k]表示在第k次操作结束时在位置(i,j)上的最大收益。
首先k这一维可以滚动数组优化掉。
然后对每个方向进行分类讨论,再对每一行/列加上一个单调队列优化即可。
注意碰到障碍就把队列清空,单调队列里的权值是dp值加(或者减)行数(或者列数)。根据不同方向分类讨论即可。

AC代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,k,x,y,t,now,dp[205][205][2],ma[205][205],ans,tp,l,r;
void work4(int t){
	for(int i=1;i<=n;i++){
		deque<int> q;
		for(int j=1;j<=m;j++){
			if(ma[i][j]){
				while(!q.empty()) q.pop_back();
				continue;
			}
			dp[i][j][now^1]=dp[i][j][now];
			while(!q.empty()&&dp[i][j][now]-j>dp[i][q.back()][now]-q.back()) q.pop_back();
			q.push_back(j);
			while(!q.empty()&&j-q.front()>t) q.pop_front();
			if(!q.empty()) dp[i][j][now^1]=max(dp[i][j][now^1],dp[i][q.front()][now]+j-q.front());
			ans=max(ans,dp[i][j][now^1]); 
		}
	}
}
void work3(int t){
	for(int i=1;i<=n;i++){
		deque<int> q;
		for(int j=m;j>=1;j--){
			if(ma[i][j]){
				while(!q.empty()) q.pop_back();
				continue;
			}
			dp[i][j][now^1]=dp[i][j][now];
			while(!q.empty()&&dp[i][j][now]+j>dp[i][q.back()][now]+q.back()) q.pop_back();
			q.push_back(j);
			while(!q.empty()&&q.front()-j>t) q.pop_front();
			if(!q.empty()) dp[i][j][now^1]=max(dp[i][j][now^1],dp[i][q.front()][now]+q.front()-j);
			ans=max(ans,dp[i][j][now^1]); 
		}
	}
}
void work2(int t){
	for(int j=1;j<=m;j++){
		deque<int> q;
		for(int i=1;i<=n;i++){
			if(ma[i][j]){
				while(!q.empty()) q.pop_back();
				continue;
			}
			dp[i][j][now^1]=dp[i][j][now];
			while(!q.empty()&&dp[i][j][now]-i>dp[q.back()][j][now]-q.back()) q.pop_back();
			q.push_back(i);
			while(!q.empty()&&i-q.front()>t) q.pop_front();
			if(!q.empty()) dp[i][j][now^1]=max(dp[i][j][now^1],dp[q.front()][j][now]+i-q.front());
			ans=max(ans,dp[i][j][now^1]); 
		}
	}
}
void work1(int t){
	for(int j=1;j<=m;j++){
		deque<int> q;
		for(int i=n;i>=1;i--){
			if(ma[i][j]){
				while(!q.empty()) q.pop_back();
				continue;
			}
			dp[i][j][now^1]=dp[i][j][now];
			while(!q.empty()&&dp[i][j][now]+i>dp[q.back()][j][now]+q.back()) q.pop_back();
			q.push_back(i);
			while(!q.empty()&&q.front()-i>t) q.pop_front();
			if(!q.empty()) dp[i][j][now^1]=max(dp[i][j][now^1],dp[q.front()][j][now]+q.front()-i);
			ans=max(ans,dp[i][j][now^1]); 
		}
	}
}
int main(){
	ios::sync_with_stdio(false);
	memset(dp,-0x3f,sizeof(dp));
	cin>>n>>m>>x>>y>>k;
	dp[x][y][0]=dp[x][y][1]=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			char c;
			cin>>c;
			if(c=='x') ma[i][j]=1;
		}
	}
	for(int i=1;i<=k;i++){
		cin>>l>>r>>tp;
		t=r-l+1;
		if(tp==1) work1(t);
		if(tp==2) work2(t);
		if(tp==3) work3(t);
		if(tp==4) work4(t);
		now^=1;
	}
	cout<<ans;
    return 0;
}

//NOI2005 Day1t1

posted @ 2021-09-02 20:27  尹昱钦  阅读(37)  评论(0编辑  收藏  举报