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 ...
随机推荐
- 通知!Symantec品牌证书已正式更名为Digicert
尊敬的合作伙伴和客户: 您好! 2017年8月2日,CA认证机构Digicert宣布正式收购 Symantec 安全认证业务.为此,Digicert宣布从2020年4月30日起,停止使用与赛门铁克(S ...
- python numpy 库
引用文章:https://blog.csdn.net/xjl271314/article/details/80409034
- SqlServer下一些实用的sql语句收集
清理数据库日志 USE [master] ALTER DATABASE [表名] SET RECOVERY SIMPLE WITH NO_WAIT ALTER DATABASE [表名] SET RE ...
- Java编程技术之浅析JVM内存
JVM JVM->Java Virtual Machine:Java虚拟机,是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的. 基本认知: ...
- MATLAB实例:多元函数拟合(线性与非线性)
MATLAB实例:多元函数拟合(线性与非线性) 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 更多请看:随笔分类 - MATLAB作图 之前写过一篇博 ...
- 使用FFT进行频谱分析
import numpy as np import matplotlib.pyplot as plt from scipy.fftpack import fft fs=100 #采样频率 N=128 ...
- (一)Log4j使用
原文链接:https://www.jianshu.com/p/eb4ac2571c94?tdsourcetag=s_pctim_aiomsg 1.先创建个maven项目,在我们项目的pom文件中导入l ...
- 视频的清晰度 1080p 720p 2k 4k是什么意思?
在bilibili上看了一些个视频,发现它视频的清晰度有很多种选法.诸如720p,1080p,2k,4k,以及我看直播时经常遇见的蓝光,超清.它们的含义分别是什么呢?为了搞清楚这个问题,也为了以后的观 ...
- 一文带你了解Redis持久化完整版本
本文讲解知识点 持久化的简介 RDB AOF RDB与AOF的区别 持久化应用场景 对于持久化这个功能点,其实很简单没有那么复杂 演示环境 centos7.0 redis4.0 redis存放目录:/ ...
- 【hdoj】哈希表题hdoj1425
hdoj1425 github链接 #include<cstdio> #include<cstring> using namespace std; const int offs ...