洛谷题目页面传送门 & AtCoder题目页面传送门

有\(1\)根数轴,Shik初始在位置\(0\)。数轴上有\(n\)只小熊,第\(i\)只在位置\(a_i\)。Shik每秒可以向左移动\(1\)个单位长度、原地不动或向右移动\(1\)个单位长度。Shik第\(1\)次到某个小熊的位置\(s\)秒后,小熊会在原地生产\(1\)个金币,Shik必须再次到达此小熊的位置才能收集金币。求Shik收集完所有金币后到达位置\(m\)所花的最小秒数。

\(n\in\left[1,10^5\right],a_i\in(0,m),a_i<a_{i+1}\)。

考虑最优情况下,Shik的路线会是怎样的。如果Shik经过了一些小熊,回头收集了这些小熊中后面一部分的金币,然后继续往终点走,留下前面一部分金币等到以后再收,这样肯定不是最优的(感性理解)。可以推出若一个小熊的金币被收了,那么它前面的所有小熊的金币都被收了,即被收了金币的小熊序列是所有小熊序列的一个前缀。考虑将某时刻的前缀分成若干个区间,每个区间内的小熊都是在一次回头中被收了金币的,于是我们就可以DP了。

设\(dp_i\)表示Shik收完了前\(i\)个小熊的金币并回到了位置\(a_i\)所花的最小秒数。不妨设\(a_0=0\)为起点。那么显然边界是\(dp_0=0\),目标是\(dp_n+m-a_n\)。转移的话,枚举当前被收了金币的小熊前缀被划分的最后一个区间的左端点的前一个小熊\(j\),即最后一次回头之前\([1,j]\)已经被收了。那么最后一次回头收的是\([j+1,i]\)。显然,路线是这样的:先将前\(j\)个小熊的金币收完,回到位置\(a_j\),然后\(a_j\to a_i\)经过\([j+1,i]\)使它们生产金币,然后\(a_i\to a_{j+1}\)回头到第\(j+1\)个小熊,等待若干秒直到第\(j+1\)个小熊生产金币,然后\(a_{j+1}\to a_i\)依次收完\([j+1,i]\)的金币并回到位置\(a_i\)。那么状态转移方程就很好列了:

\[dp_i=\min_{j=0}^{i-1}\{dp_j+(a_i-a_j)+(a_i-a_{j+1})+\max\left(0,s-2(a_i-a_{j+1})\right)+(a_i-a_{j+1})\}
\]

\[dp_i=\min_{j=0}^{i-1}\{dp_j+3a_i-a_j-2a_{j+1}+\max\left(0,s-2a_i+2a_{j+1}\right)\}
\]

暴力转移显然是\(\mathrm O\!\left(n^2\right)\)的,于是考虑优化。注意到方程里有个\(\max\)很不好处理,于是分类讨论,分成\(s-2a_i+2a_{j+1}\ge0\)和\(s-2a_i+2a_{j+1}<0\)这\(2\)种。此时方程变为了:(化简后)

\[dp_i=\min\!\left(\min_{j\in[0,i),s-2a_i+2a_{j+1}\ge0}\{dp_j+a_i-a_j+s\},\min_{j\in[0,i),s-2a_i+2a_{j+1}<0}\{dp_j+3a_i-a_j-2a_{j+1}\}\right)
\]

将关于决策变量\(j\)的放到一起,关于状态变量\(i\)的和常量放到一起,得

\[dp_i=\min\!\left(\min_{j\in[0,i),2a_{j+1}\ge 2a_i-s}\{(dp_j-a_j)+(a_i+s)\},\min_{j\in[0,i),2a_{j+1}<2a_i-s}\{(dp_j-a_j-2a_{j+1})+3a_i\}\right)
\]

\(2\)个\(\min\)的条件里的\(2a_{j+1}\)显然有单调性,所以\(2\)个\(\min\)取的\(j\)都构成区间。特殊地,对于第\(2\)个\(\min\),是前缀,即左端点为\(0\)的区间。又因为\(2a_i-s\)也有单调性,所以第\(1\)个\(\min\)的区间左端点单调递增,对于每个\(i\),这个左端点可以two-pointers求出。于是对于第\(1\)个\(\min\)维护单调队列,对于第\(2\)个\(\min\)维护前缀最小值,\(\mathrm O(n)\)。

下面贴代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long//防爆int
const int inf=0x3f3f3f3f3f3f3f3f;
const int N=100000;
int n/*小熊个数*/,m/*终点*/,s/*小熊被Shik碰到至生产金币之间的秒数*/;
int a[N+1];//小熊的位置
int dp[N+1];//dp[i]表示Shik收完了前i个小熊的金币并回到了位置a[i]所花的最小秒数
int q[N],head,tail;//对于第1个min维护的单调队列
signed main(){
cin>>n>>m>>s;
for(int i=1;i<=n;i++)cin>>a[i];
q[tail++]=0;//i=1,j=0满足2a[j+1]>=2a[i]-t,归第1个min,于是压入单调队列
int now=-1/*第2个min取的j构成的区间(前缀)的右端点*/,mn=inf/*当前的前缀最小值*/;
for(int i=1;i<=n;i++){
while(now+1<i&&2*a[now+2]<2*a[i]-s)now++,mn=min(mn,dp[now]-a[now]-2*a[now+1]);//将now往后移
while(head<tail&&q[head]<=now)head++;//维护单调队列,弹出过时元素
while(head<tail&&dp[q[tail-1]]-a[q[tail-1]]>=dp[i-1]-a[i-1])tail--;//维护单调队列队尾严格单调递增性
q[tail++]=i-1;//将j=i-1入队
dp[i]=min(dp[q[head]]-a[q[head]]+a[i]+s,mn+3*a[i]);//状态转移方程
}
cout<<dp[n]+m-a[n]<<"\n";//目标
return 0;
}

AtCoder agc007_d Shik and Game的更多相关文章

  1. AtCoder AGC007E Shik and Travel (二分、DP、启发式合并)

    题目链接 https://atcoder.jp/contests/agc007/tasks/agc007_e 题解 首先有个很朴素的想法是,二分答案\(mid\)后使用可行性DP, 设\(dp[u][ ...

  2. 【AtCoder Grand Contest 007E】Shik and Travel [Dfs][二分答案]

    Shik and Travel Time Limit: 50 Sec  Memory Limit: 512 MB Description 给定一棵n个点的树,保证一个点出度为2/0. 遍历一遍,要求每 ...

  3. AtCoder Grand Contest 007 E:Shik and Travel

    题目传送门:https://agc007.contest.atcoder.jp/tasks/agc007_e 题目翻译 现在有一个二叉树,除了叶子每个结点都有两个儿子.这个二叉树一共有\(m\)个叶子 ...

  4. AtCoder Grand Contest 007

    AtCoder Grand Contest 007 A - Shik and Stone 翻译 见洛谷 题解 傻逼玩意 #include<cstdio> int n,m,tot;char ...

  5. AtCoder刷题记录

    构造题都是神仙题 /kk ARC066C Addition and Subtraction Hard 首先要发现两个性质: 加号右边不会有括号:显然,有括号也可以被删去,答案不变. \(op_i\)和 ...

  6. AtCoder Regular Contest 061

    AtCoder Regular Contest 061 C.Many Formulas 题意 给长度不超过\(10\)且由\(0\)到\(9\)数字组成的串S. 可以在两数字间放\(+\)号. 求所有 ...

  7. AtCoder Grand Contest 001 C Shorten Diameter 树的直径知识

    链接:http://agc001.contest.atcoder.jp/tasks/agc001_c 题解(官方): We use the following well-known fact abou ...

  8. AtCoder Regular Contest 082

    我都出了F了……结果并没有出E……atcoder让我差4分上橙是啥意思啊…… C - Together 题意:把每个数加1或减1或不变求最大众数. #include<cstdio> #in ...

  9. AtCoder Regular Contest 069 D

    D - Menagerie Time limit : 2sec / Memory limit : 256MB Score : 500 points Problem Statement Snuke, w ...

随机推荐

  1. Jmeter BeanShell笔记

    前言:beanshell是支持java语法的,因此当一些复杂的数据结构jmeter处理不了的时候,我们可以借助于java来实现 1,使用beanshell处理JDBC请求返回的值 数据库结构 当JDB ...

  2. happen-before原则

    单线程happen-before原则:      在同一个线程中,书写在前面的操作happen-before后面的操作. 锁的happen-before原则:          同一个锁的unlock ...

  3. Java面向对象封装优化2_构造方法

    1. 类 package cn.itcast.day06.demo05; /* 一个标准的类通常要拥有下面四个组成部分: 1. 所有的成员变量都要使用private关键字修饰 2. 为每一个成员变量编 ...

  4. C语言:把分数最低的学生数据放入数组b所指的数组中,-从键盘输入若干字符串,写入文件myfile4中,用-1作字符输入结束的标志,

    //学生记录由学号和成绩组成,N名学生的数据已放入主函数中的结构体数组中,fun函数:把分数最低的学生数据放入数组b所指的数组中,分数最低的学生可能不止一个.人数返回. #include <st ...

  5. 跨域-JSONP

    jsonp跨域 - 前端适配,后台配合 说明:前后台同时改造 cnpm i jsonp --save-dev 在App.vue里 import jsonp from 'jsonp' let url = ...

  6. MS17_010漏洞攻击Windows7

    攻击主机系统:Kali Linux 2018 目标主机系统:Windows7 x64 1.攻击主机启动Metasploit: msfconsole 2.查找MS17_010漏洞相关的信息: searc ...

  7. javascript的正则匹配

    前段时间需要用到比较多的js代码,当时有点搞不清test和match方法的区别,向百度求助,找到了这边关于正则匹配的博文,感谢作者分享. 原文地址[http://blog.sina.com.cn/s/ ...

  8. Perl 笔记

    目录 Perl 学习 常用记录 基础 1. 运行perl 2. 字符串 3. 变量 4. 条件 5. 循环 6. 运算符 7. 时间日期 8. 子程序(函数) 9. 引用 10. 格式化输出 11. ...

  9. 搭建一个ssm框架的maven项目需要配置的文件

    单独功能需要的配置文件: 1,mybatis配置文件      mybatis-config.xml2,spring配置文件        spring-context.xml  ......3,we ...

  10. JS清除空格之trim()方法

    JQ: $.trim() 函数用于去除字符串两端的空白字符. 注意:$.trim()函数会移除字符串开始和末尾处的所有换行符,空格(包括连续的空格)和制表符.如果这些空白字符在字符串中间时,它们将被保 ...