Cow Hopscotch (单调队列 + DP)
链接:https://ac.nowcoder.com/acm/contest/1113/K
来源:牛客网
The cows have reverted to their childhood and are playing a game similar to human hopscotch. Their hopscotch game features a line of N (3 <= N <= 250,000) squares conveniently labeled 1..N that are chalked onto the grass.
Like any good game, this version of hopscotch has prizes! Square i is labeled with some integer monetary value ViV_iVi (-2,000,000,000 <= ViV_iVi <= 2,000,000,000). The cows play the game to see who can earn the most money.
The rules are fairly simple:
* A cow starts at square '0' (located just before square 1; it has no monetary value).
* She then executes a potentially empty sequence of jumps toward square N. Each square she lands on can be a maximum of K (2 <= K <= N) squares from its predecessor square (i.e., from square 1, she can jump outbound to squares 2 or 3 if K==2).
* Whenever she wishes, the cow turns around and jumps back towards square 0, stopping when she arrives there. In addition to the restrictions above (including the K limit), two additional restrictions apply:
* She is not allowed to land on any square she touched on her outbound trip (except square 0, of course).
* Except for square 0, the squares she lands on during the return trip must directly precede squares she landed on during the outbound trip (though she might make some larger leaps that skip potential return squares altogether).
She earns an amount of money equal to the sum of the monetary values of all the squares she jumped on. Find the largest amount of cash a cow can earn.
By way of example, consider this six-box cow-hopscotch course where K has the value 3:
Square Num: 0 1 2 3 4 5 6
+---+ +---+ +---+ +---+ +---+ +---+ +---+
|///|--| |--| |--| |--| |--| |--| |
+---+ +---+ +---+ +---+ +---+ +---+ +---+
Value: - 0 1 2 -3 4 5
One (optimal) sequence Bessie could jump (shown with respective bracketed monetary values) is: 1[0], 3[2], 6[5], 5[4], 2[1], 0[0] would yield a monetary total of 0+2+5+4+1+0=12.
If Bessie jumped a sequence beginning with 0, 1, 2, 3, 4, ... then she would be unable to return since she could not legally jump back to an untouched square.
输入描述:
* Line 1: Two space separated integers: N and K
* Lines 2..N+1: Line i+1 contains a single integer: ViV_iVi
输出描述:
* Line 1: A single line with a single integer that is the maximum amount of money a cow can earn
题意:给定一个 n 个格子,每个格子有一个价值,一头牛一开始在 0 格子,每次最多跳 k 个,每当它跳到某个格子上,它就能够获得该格子的价值,并且它随时可以往后跳,但是有两 个限制,一个就是不能再跳已经跳过的格子,再就是必须跳到以前曾经跳过的格子的前一个,直到它跳到 0 格子结束,求它最多能获得多少价值。
析:很容易看出来是一个DP,但是有一个条件特别烦,那就是必须要回来,这个就是对后面的状态有影响,我们必须要消除这个影响,那就是在向前跳的时候就要把已经往后跳的格子也一块算出来,就没有影响了,dp[i] 表示跳到 i 位置,并且 i-1位置是回来要跳的格子,dp[i] = max{dp[j] | i-j >= k && j <= i-2}, 这个状态方程很容易写出来,但是它是不对的,为什么是不对的呢,因为如果 i-k ~ i-2 这些格子中可能它在向前的时候也跳过了,只不过在往后跳的时候没跳过,这样的格子我们没有计算过,再考虑这些格子肯定都是正数,我们不可能去跳负数。状态方程就改变成了 dp[i] = max{dp[j] + sum[i-2]-sum[j] | i-j >= k && j <= i-2},这里 sum[i] 是表示 1~i 这个区间内的所有正数的和。还有一个问题就是 k 太大了,所以直接循环是肯定要超时的,可以使用单调队列来优化, 单调队列中只要比较 dp[j] - sum[j] 就好了,因为sum[i-2]是一个常数,没有啥必要。还要考虑一些特殊情况,比如返回时只直接跳到0,等一些特殊情况。
代码如下:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#include <sstream>
#include <list>
#include <assert.h>
#include <bitset>
#include <numeric>
#define debug() puts("++++")
#define gcd(a, b) __gcd(a, b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a, b, sizeof a)
#define sz size()
#define be begin()
#define ed end()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
// #define all 1,n,1
#define FOR(i,n,x) for(int i = (x); i < (n); ++i)
#define freopenr freopen("in.in", "r", stdin)
#define freopenw freopen("out.out", "w", stdout)
using namespace std; typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e17;
const double inf = 1e20;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 250000 + 10;
const int maxm = 1e6 + 10;
const LL mod = 998244353LL;
const int dr[] = {-1, 1, 0, 0, 1, 1, -1, -1};
const int dc[] = {0, 0, 1, -1, 1, -1, 1, -1};
const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
int n, m;
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline bool is_in(int r, int c) {
return r >= 0 && r < n && c >= 0 && c < m;
}
inline int readInt(){ int x; scanf("%d", &x); return x; } LL dp[maxn], sum[maxn];
int a[maxn], q[maxn]; int main(){
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i){
scanf("%d", a + i);
sum[i] = sum[i-1] + (a[i] > 0 ? a[i] : 0);
}
LL ans = sum[min(n, m)];
int front = 0, rear = 0;
q[rear++] = 1;
dp[1] = a[1];
for(int i = 2, j = 0; i <= n; ++i, ++j){
while(front < rear && i - q[front] > m) ++front;
LL val = dp[j] - sum[j];
while(front < rear && val >= dp[q[rear-1]] - sum[q[rear-1]]) --rear;
q[rear++] = j;
int x = q[front];
dp[i] = dp[x] + a[i] + a[i-1] + sum[i-2] - sum[x];
}
for(int i = 1; i <= n; ++i)
ans = max(ans, dp[i] + sum[min(n, i-1+m)] - sum[i]);
printf("%lld\n", ans);
return 0;
}
Cow Hopscotch (单调队列 + DP)的更多相关文章
- POJ 3017 单调队列dp
Cut the Sequence Time Limit: 2000MS Memory Limit: 131072K Total Submissions: 8764 Accepted: 2576 ...
- [TyvjP1313] [NOIP2010初赛]烽火传递(单调队列 + DP)
传送门 就是个单调队列+DP嘛. ——代码 #include <cstdio> ; , t = , ans = ~( << ); int q[MAXN], a[MAXN], f ...
- zstu 4237 马里奥的求救——(单调队列DP)
题目链接:http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4237 这题可以转化为每次可以走g~d+x步,求最大分数,且最大分数的步数最少. ...
- 1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP
1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP 题意 用摄像机观察动物,有两个摄像机,一个可以放在奇数天,一个可以放在偶数天.摄像机在 ...
- BZOJ 5281--[Usaco2018 Open]Talent Show(分数规划&单调队列&DP)
5281: [Usaco2018 Open]Talent Show Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 79 Solved: 58[Sub ...
- vijos P1243 生产产品(单调队列+DP)
P1243生产产品 描述 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产 品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器 ...
- POJ 1821 单调队列+dp
题目大意:有K个工人,有n个墙,现在要给墙涂色.然后每个工人坐在Si上,他能刷的最大范围是Li,且必须是一个连续子区间,而且必须过Si,他刷完后能获得Pi钱 思路:定义dp[i][j]表示前i个人,涂 ...
- codeforces 1077F2. Pictures with Kittens (hard version)单调队列+dp
被队友催着上(xun)分(lian),div3挑战一场蓝,大号给基佬紫了,结果从D开始他开始疯狂教我做人??表演如何AKdiv3???? 比赛场上:A 2 分钟,B题蜜汁乱计数,结果想得绕进去了20多 ...
- 【LOJ#10180】烽火传递 单调队列+dp
题目大意:给定一个 N 个非负整数数组成的序列,每个点有一个贡献值,现选出其中若干数,使得每连续的 K 个数中至少有一个数被选,要求选出的数贡献值最小. 题解:设 \(dp[i]\) 表示考虑了序列前 ...
随机推荐
- mui ajax传参示例
//加入购物车var data=[];var row1 = {good_id:'1',number:'2',goods_spec_ids:[1,2]};data.push(row1);console. ...
- Hadoop 之 HDFS API操作
1. 文件上传 @Slf4j public class HDFSClient { @Test public void testCopyFromLocalFile() throws Exception{ ...
- linux中学习中提炼出来的命令
Linux: 基于debain的系统(如:Ubuntu等)pms基本工具:aptitude[apt-get],dpkgaptitude search package_name 查看软件包是否已安装,如 ...
- 火狐 , IE , 谷歌浏览器的 驱动下载地址汇总
一.Firefox和驱动下载地址 所有火狐浏览器版本下载地址:http://ftp.mozilla.org/pub/firefox/releases/ 所有火狐驱动geckodriver版本下载地址: ...
- 【Python基础】12_Python中的容器类型公共方法
1.Python中的内置函数 注:比较两个值,使用 <. >. == 2.切片 注:字典是一个无序集合,不能切片 3.运算符 字典中的in .not in 对字段操作时,只能判断字典的k ...
- linux下mysql启动 Starting MySQL. ERROR! The server quit without updating PID file(xxx/x.pid)
service mysql start 报错: Starting MySQL. ERROR! The server quit without updating PID file(xxx/x.pid) ...
- 第6章:使用Python监控Linux系统
1.Python编写的监控工具 1).多功能系统资源统计工具dstat dstat是一个用Python编写的多功能系统资源统计工具,用来取代Linux下的vmstat,iostat,netstat和i ...
- shell习题第19题:最常用的命令
[题目要求] 查看使用最多的10个命令 [核心要点] history 或者 ~/.bash_history sort uniq [脚本] #!/bin/bash # history就是调用cat ~/ ...
- Jmeter4.0---- 修改jmeter源代码(18)
1.说明 jmeter本身功能很强大,但是在使用的时候我们会发现有些想法jmeter无法帮我们实现,这个时候就需要我们细节去修改一下它的源代码,来满足我们的需求. * 仅供参考 2.步骤 第一步: j ...
- 前端vue项目执行npm install 报错cd() never called()
前端我刚开始接触Vue,从GitHub上下载了代码程序,但缺少一些插件,用vscode打开并下载插件执行报错cd() never called! 解决的方式 1.执行cmd命令行不要再vscode里执 ...