• 洛谷 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

  • 相关阅读:
    python中深浅复制教程
    jquery easyui打开新的tab实现遮罩效果
    经典逻辑题 百人戴帽子问题
    JAVA反射机制示例 简单的Ioc实现
    Java研修录003标识符
    应该怎么管理程序员?
    内网VSFTP服务器的搭建
    如何彻底关闭WIN10防火墙
    使用 Visual Studio 调试器附加到正在运行的进程
    Qt+VS2019 英文翻译
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15220663.html
Copyright © 2020-2023  润新知