洛谷题目页面传送门 & 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. 在 Fabric 中使用私有数据

    本教程将演示收集器(collection)的使用,收集器为区块链网络上已授权的组织节点 提供私有数据的存储和检索. 本教程假设您已了解私有数据的存储和他们的用例.更多的信息请参阅 私有数据 . 本教程 ...

  2. 查看svn 提交记录

    svn log -v -r {2019-8-11}:{2019-8-16} -l 30 | sed -n '/wangyue01/,/--$/ p'其中:-r {2018-9-10}:{2018-9- ...

  3. 在linux环境下python与C++混合编程

    参考:在linux环境下编译C++ 程序 linux下python3调用c代码或者python3调用c++代码 https://blog.csdn.net/u013179327/article/det ...

  4. 洛谷P1049装箱问题(01背包)

    题目描述 有一个箱子容量为VVV(正整数,0≤V≤200000 \le V \le 200000≤V≤20000),同时有nnn个物品(0<n≤300<n \le 300<n≤30, ...

  5. 聊聊Redis的持久化

    两种持久化策略 1.AOF:记录每一次的写操作到日志上,重启时重放日志以重建数据2.RDB:每隔一段时间保存一次当前时间点上的数据快照    快照就是一次又一次地从头开始创造一切3.可以关闭持久化4. ...

  6. 洛谷 P3865 【模板】ST表(模板)

    嗯... 题目链接:https://www.luogu.com.cn/problem/P3865 ST(Sparse Table)算法,运用了倍增的思想. 我们令f[i][k]数组表示区间[i, i ...

  7. Ubuntu系统中创建虚拟环境

    1.虚拟环境产生的原因:如果在一台电脑上, 想开发多个不同的项目, 需要用到同一个包的不同版本, 如果使用上面的命令, 在同一个目录下安装或者更新, 新版本会覆盖以前的版本, 其它的项目就无法运行了. ...

  8. POJ-1087 A Plug for UNIX (网络流)

    思路 电器数1 ~ 100,附带100种接口,注意题目:You notice that some of the devices use plugs for which there is no rece ...

  9. IDEA 下的 github 创建提交与修改

    本章假定你已经安装了 git 客户端,本文仅仅使用与 Mac 环境下,未在 Window下实验,但 IDEA 在 Window 和 Mac 下软件的使用方法是一致的. 1 配置账号 IDEA 需要配置 ...

  10. 关于java继承条件下的构造方法调用

    首先是测试代码: class Grandparent { public Grandparent() { System.out.println("GrandParent Created.&qu ...