• 洛谷 P3800 Power收集(单调队列优化dp)


    传送门


    解题思路

    很显然的一个线性dp,设dp[i][j]为到第i行第j列的最大power。
    可以从前一行dp[i-1][j-t]~dp[i-1][j+t]转移过来。
    用单调队列优化一下即可。
    防止MLE可以用滚动数组优化,然后k个P点用二维map存一下。
    注意:
    不能直接

    dp[j][now^1]=dp[q.front()][now]+ma[i][j]
    

    因为ma[i][j]如果没有会自动开一个空间(i,j)并赋初值0。
    正确操作应该是

    dp[j][now^1]=dp[q.front()][now];
    if(ma[i].find(j)!=ma[i].end()) dp[j][now^1]+=ma[i][j];
    

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<cmath>
    #include<algorithm>
    #include<map>
    #include<queue>
    using namespace std;
    map<int,map<int,int> > ma;
    int n,m,k,t,ans=-1e9,dp[4005][2],now;
    int main(){
    	ios::sync_with_stdio(false);
    	cin>>n>>m>>k>>t;
    	for(int i=1;i<=k;i++){
    		int x,y,v;
    		cin>>x>>y>>v;
    		ma[x][y]=v;
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++) dp[j][now^1]=0;
    		deque<int> q;
    		for(int j=1;j<=t;j++) {
    			while(!q.empty()&&dp[j][now]>dp[q.back()][now]) q.pop_back();
    			q.push_back(j);
    		}
    		for(int j=1;j<=m;j++){
    			if(!q.empty()&&j-q.front()>t) q.pop_front();
    			while(!q.empty()&&j+t<=m&&dp[j+t][now]>dp[q.back()][now]) q.pop_back();
    			if(j+t<=m) q.push_back(j+t);
    			dp[j][now^1]=dp[q.front()][now];
    			if(ma[i].find(j)!=ma[i].end()) dp[j][now^1]+=ma[i][j];
    			if(i==n) ans=max(ans,dp[j][now^1]);
    		}
    		now^=1;
    	}
    	cout<<ans;
        return 0;
    }
    
  • 相关阅读:
    受得了多大的委屈,才做得了多大的事
    黑客常用 Linux 入侵常用命令
    8年软件测试工程师感悟——写给还在迷茫中的朋友
    买or不买?如何测试博彩公司赔率是否合理?
    函数三
    函数二
    函数
    字符编码与文件的操作
    三、元组,字典、集合
    3.20学习内容,字符串与列表
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15216578.html
Copyright © 2020-2023  润新知