zoukankan      html  css  js  c++  java
  • P1725 题解

    P1725 琪露诺

    前排声明一下qwq,蒟蒻刚学OI没多久,而且是自学的,写的比较累赘,望见谅

    原题面

    大致题意

    给编号为0~N的N+1个数,每个格子都有一个冰冻指数ice[i]

    每一个格子都可以转移到区间[i+l,i+r]上,求ice[i]总和的最大值


    很明显可以看出这是一道dp的题

    我们不妨先把转移方程写出来

    题目中说每一个格子都可以转移到区间[i+l,i+r]上

    不难推出转移方程:

    • (~~~~~~~~~~~~~~~~dp_i=max(dp_{i-r},dp_{i-r+1},...dp_{i-l-1},dp_{i-l})+ice[i])

    (放张图 样例是自造的,此图为i=4的情况)

    因此,对于每一个(dp_i)来说

    他的值均是由[(dp_{i-l})~(dp_{i-r})]区间中的最大值转移过来的(前面方程也说了)

    而且这个区间是不断滑动的

    滑动区间求最值,很容易联想到单调队列

    照题目里的数据范围普通的dp肯定会超时

    因此我们可以用单调队列来优化它

    做了一个比较粗糙的过程动态图qwq

    补几张gif跳的比较快的图

    (dp_1)


    • (dp_2)

    • 以此类推,均由[(dp_{i-l})~(dp_{i-r})]区间中的最大值转移过来

    写的貌似有点累赘...

    如有错误还请dalao们指出qwq,话说没人会来看这么辣鸡的题解吧

    贴个丑陋的代码:

    #include<bits/stdc++.h>
    using namespace std;
    int ice[300010],dp[300010],q[300010];
    int l,n,r,ans=-1<<30;
    int head=1,tail=0;
    void findmax(){
    	for(int i=l;i<=n;i++){
    		
    		while(head<=tail&&dp[q[tail]]<dp[i-l]) tail--;//单调队列 
    		while(head<=tail&&q[head]<i-r) head++;//滑动区间 
    		q[++tail]=i-l;
    		dp[i]=dp[q[head]]+ice[i];//转移 
    		
    		if(i>=n-r+1) ans=max(ans,dp[i]);//在开始移动的时候求最大值 
    	}
    }
    int main(){
    	cin>>n>>l>>r;
    	for(int i=0;i<=n;i++){
    		scanf("%d",&ice[i]);
    	}
    	memset(dp,0xcf,sizeof(dp));dp[0]=0;//注意,ice的值可能为负,所以要把dp跟ans的值赋为无穷小,一开始在这里卡了好久... 
    	findmax();
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    Linux命令:mapfile
    Linux命令:logout
    行式数据库和列式数据库的浅析
    hadoop常见错误集锦
    hadoop环境搭建遇到问题集锦
    杀毒的一点学习
    powerdesigner的学习
    突然的想法
    shell脚本入门教程(转)
    java classpath深入详解(转)
  • 原文地址:https://www.cnblogs.com/xcxc82/p/13339561.html
Copyright © 2011-2022 走看看