JSOI2016 病毒感染(动态规划)
题目传送门:洛谷P5774
思路来源:郭大佬(我就是凑不要脸的白嫖党 : P)
题目分析:
我们一点点来分析这道题:
- 起点固定为1号,所有村庄是按线性排列的,而不是图,所以我们应该用线性DP(废话 )
 - 每到达一个村庄,我们都有两种选择:一是治好这个村庄的所有人,二是直接莽到下一个村庄(当然也可以回头);而每一种操作都需要消耗一天的时间(时间是这道题最恶心的地方)
 - 而如果我们选择莽过了一个村子,那么一旦我们在后面某一个时间选择往回走,就必须回来把这个村子给治好,并且在返回的途中也是可以顺手治好顺路的村子的(莽夫操作)
 - 对于同一个村庄,病毒只会在自己的一座村子里扩散,而且每天领盒饭的人数都是一定的,(@某新冠病毒,你看看人家多听话 Σ( ° △ °|||)︴)
 
然后,沿着大佬的路子走,我们定义 dp[i] 为治好1~i个村庄所要领盒饭的人数,鉴于我们有两种操作,需要枚举中间点K,但时间效率很糟糕。所以我们必须优化。
我们都能看出来吃时间的主要是操作二,也就是计算:如果我们选择先莽过某一个村庄,然后再回来治好它,这期间领盒饭的人数;
所以,我们选择新定义一个 g[i][j] 来表示从j点一路莽到i点,再从i点回到j点治好j点,然后再回到i点,这一段时间内i到j区间内的盒饭数;
明白了g数组的含义,那么来考虑g数组的转移,依然是动态规划的老三样:
阶段肯定不用我说,就是前 i 个,我们依次遍历即可;
然后是状态,我们肯定是要枚举 j 的,那这里就要考虑到 j 的枚举顺序。由于每天每个村庄领盒饭的人都是一定的,所以我们可以通过在一开始预处理出前缀和来轻松求出区间内每天的盒饭数。那么,实际上影响总盒饭数的就只有时间这一项。然后,回归我们 g[i][j] 的定义,无论我们选择救还是莽,我们的 g[i][j] 势必要从 g[i][j+1] 转移来,为什么呢?因为 g[i][j] 是 j 到 i 区间内的盒饭数,时间也是 j 到 i 的时间,那么 j+1 在空间上离 i 更近,所以所用的时间也是 j+1 到 i 更少,我们的转移必然是从用时更少的、盒饭较少的一点点向更多的转移,反映到状态上就是我们要从倒序枚举 j ,即从 i-1 到 1 来枚举 j;
最后是转移方程:
- 我们的决策无非两种:救 or 莽——救的话很好考虑,因为救人需要一天时间,所以后面的 j+1 到 i 的村子里的人必然要领上一波便当,直接累加一个区间的前缀和即可;如果莽的话,我们必须弄明白用时到底是多少:首先,我们要明白,对于 j 到 i 这段路程,我们来回一共走了三遍,j 到 i ,i 到 j ,j 再到 i 。然后,如果我们选择莽,第一遍从 j 到 i ,则 j 到 i 会领上好几波便当,到底几次我们想一想,或者数数手指也行,就是 i-j 对不对。
 - 第二遍从 i 回到 j ,由于我们第一遍是直接莽过来的,所以我们在回来的时候必须把路上所有村子都治好,也就是说,我们回来所用的时间应该是单纯莽的二倍,所以,再算上第一遍的,这个 j 村一共要领上 3*(i-j)波便当
 - 第三遍时从 j 村回到 i 村,由于我们已经把路上所有村子都治好了,所以 j 到 i 不会再有便当,所以 g 就不用再管了,但赶路是需要 i-j 的时间的,所以后面的 i+1 到 n 还会再 领上一波便当,也就是说,i 后面的实际上领了四波便当,(当然,这是 dp 数组的转移),我们现在先写出 g[i][j] 的转移方程:
 g[i][j]=g[i][j+1]+Calc(j+1,i)+min((3ll*(i-j)*a[j],Calc(j+1,i))
- 函数:Calc ( l ,r ) { return s[ r ] - s[ l -1 ] ; } s是前缀和
 
到这里,其实这道题就已经完成一大半了,有了 g[i][j] 作为辅助,dp[i]的转移实际上就很简单了,我们只需要在 g[i][j+1] 的基础上累加上 i 后面的部分即可,要注意的就是我上边提到的要乘4次
dp[i]=min(dp[i],dp[j]+g[i][j+1]+Calc(i+1,n) * ((i-(j+1)) * 4+2));
- 另外需要注意的是我们在 j 和 j+1 来回各需要一天,最后别忘了加个2
 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=3000+5;
int a[maxn];
long long s[maxn],dp[maxn],g[maxn][maxn];
long long Calc(int l,int r){
    return s[r]-s[l-1];
}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        s[i]=a[i]+s[i-1];
    }
    memset(dp,0x3f,sizeof(dp));
    for(int i=1;i<=n;i++)
    for(int j=i-1;j>=1;j--)
        g[i][j]=g[i][j+1]+Calc(j+1,i)+min((long long)3*(i-j)*a[j],Calc(j+1,i));
    dp[0]=0;
    for(int i=1;i<=n;i++)
    for(int j=0;j<i;j++)
        dp[i]=min(dp[i],dp[j]+g[i][j+1]+Calc(i+1,n)*((i-(j+1))*4+2));
    cout<<dp[n]<<endl;
    return 0;
}
												
											JSOI2016 病毒感染(动态规划)的更多相关文章
- BZOJ4856 JSOI2016 病毒感染 区间DP
		
传送门 原Word文档 题意:太长不给 这种题目一看就是区间DP 设$f_i$表示治愈了前$i$个村子的时候最少死了多少村民,又设前缀和为$sum_i$,通过枚举折返时最后经过的村子$j$,并且提前计 ...
 - [JSOI2016]病毒感染[dp]
		
题意 有 \(n\) 个村庄按标号排列,每个村庄有一个死亡速度 \(a_i\) 表示每天死 \(a_i\) 人(除非你治好这个村庄). 你从 1 号村庄出发,每天可以选择向相邻的村庄进发或者治愈 ...
 - P5774 [JSOI2016]病毒感染
		
题目描述 JOSI 的边陲小镇爆发了严重的 Jebola 病毒疫情,大批群众感染生命垂危.计算机科学家 JYY 采用最新的算法紧急研制出了 Jebola 疫苗,并火速前往灾区救治患者. 一共有 NN ...
 - 区间dp提升复习
		
区间\(dp\)提升复习 不得不说这波题真的不简单... 技巧总结: 1.有时候转移可以利用背包累和 2.如果遇到类似区间添加限制的题可以直接把限制扔在区间上,每次只考虑\([l,r]\)被\([i, ...
 - [JSOI2016]无界单词[动态规划、kmp]
		
题意 题目链接 分析 对于第一问,枚举最终串最小的相同前后缀来统计答案. 由于最小的相同前后缀也是无界单词,所以可以考虑先求解子问题. 定义状态 \(f(i)\) 表示长度为 \(i\) 的串中有多少 ...
 - 【LOJ】#2080. 「JSOI2016」病毒感染
		
题解 那个限制表示一回头要治完前面的所有病人 我们处理一个g[i][j]表示治疗i到j的病人至少会死多少病人 \(g[i][j] = g[i + 1][j] + sum[i + 1,j] + min( ...
 - BZOJ4856 病毒感染 [Jsoi2016] dp
		
正解:区间dp+辅助dp 解题报告: 先放个传送门qwq 然后这题,又是一道看不懂题目的玩意儿:( 大概是语文太差 那就先解释下 其实只是一个点比较难明白就是它港 "假设JYY 进入i村庄并 ...
 - 增强学习(三)----- MDP的动态规划解法
		
上一篇我们已经说到了,增强学习的目的就是求解马尔可夫决策过程(MDP)的最优策略,使其在任意初始状态下,都能获得最大的Vπ值.(本文不考虑非马尔可夫环境和不完全可观测马尔可夫决策过程(POMDP)中的 ...
 - 简单动态规划-LeetCode198
		
题目:House Robber You are a professional robber planning to rob houses along a street. Each house has ...
 
随机推荐
- PAT 在霍格沃茨找零钱
			
如果你是哈利·波特迷,你会知道魔法世界有它自己的货币系统 —— 就如海格告诉哈利的:“十七个银西可(Sickle)兑一个加隆(Galleon),二十九个纳特(Knut)兑一个西可,很容易.”现在,给定 ...
 - CDN百科第三讲 | 如果用了云服务器,还需要做CDN加速吗?
			
在全站上云的背景下,云计算已经不仅仅是大型互联网公司的独享概念,正在被更多的传统企业.中小企业甚至个人站长所采用.在众多云计算服务中,最常见两个产品就是云服务器和CDN,今天的CDN百科第三讲,就给大 ...
 - mybatis技术总结
			
一.框架概述 day1 1.什么是框架 框架是系统的可重用设计,是对J2EE底层技术的封装(JDBC,IO流,多线程,Servlet,Socket). 2.框架解决了哪些问题? 1.解决了技术整合问题 ...
 - 温故知新-java多线程&深入理解线程池
			
文章目录 摘要 java中的线程 java中的线程池 线程池技术 线程池的实现原理 简述 ThreadPoolExecutor是如何运行的? 线程池运行的状态和线程数量 任务执行机制 队列缓存 Wor ...
 - 基于Azure IoT开发.NET物联网应用系列-全新的Azure IoT架构
			
物联网技术已经火了很多年了,业界各大厂商都有各自成熟的解决方案.我们公司主要搞新能源汽车充电,充电桩就是物联网技术的最大应用,车联网.物联网.互联网三网合一.2017年的时候重点研究过Azure Io ...
 - 从零开始的Spring Boot(4、Spring Boot整合JSP和Freemarker)
			
Spring Boot整合JSP和Freemarker 写在前面 从零开始的Spring Boot(3.Spring Boot静态资源和文件上传) https://www.cnblogs.com/ga ...
 - postman切换环境
			
原文链接:https://www.cnblogs.com/nicole-zhang/p/11498384.html 通常会有多个测试环境,针对同一个接口来说,可能只是域名有变化,此时可以添加postm ...
 - Jmeter(十) - 从入门到精通 - JMeter逻辑控制器 - 中篇(详解教程)
			
1.简介 Jmeter官网对逻辑控制器的解释是:“Logic Controllers determine the order in which Samplers are processed.”. 意思 ...
 - MQ系列(1)——rabbitMQ简介
			
前文我们学习了 MQ的相关知识,现在我们来学习一下实现了AMQP协议的 rabbitMQ 中间件.rabbitMQ 是使用 erlang 语言编写的中间件(erlang之父 19年4月去世的,很伟大一 ...
 - cc28c_demo.cpp,派生类的构造函数和析构函数-代码示范3
			
cc28c_demo.cpp,派生类的构造函数和析构函数-代码示范3 //派生类的构造函数和析构函数//派生类的构造函数(执行步骤)//--执行基类的构造函数//--执行成员对象的构造函数//--执行 ...