@description@

给定一个含 N 个数的序列,Alice 与 Bob 在博弈。Alice 先手,轮流进行 N 次操作。

每一次操作会选择一个之前未选中的数,且与上一个玩家选择的数相邻。

如果是第一次或者上一次选择的数周围没有未被选中的数,则可以任意选择一个数。

两个人都想要最大化自己所选择的数之和,且都采取最优策略,求最后 Alice 选择的数之和与 Bob 选择的数之和。

原题连接。

@solution@

首先考虑第一次操作对应的几种可能性。

第一,先手可以直接取最左边/最右边,则接下来的方案唯一。

第二,先手选择一个中间的数 x,后手决定选 x 的左边还是右边。

考虑第二种情况,如果 x 的左边/右边有奇数个数,先手可能会被动地变成后手。

而此时,后手存在一种可能的取数方法,对应着先手一开始取最左边/最右边的方案。

也就是说此时后手的最优策略一定不劣于先手一开始取最左边/最右边的方案,这对先手而言不利,所以先手绝对不会让出主动权。

那么这意味着如果先手选择第二类情况,那么选择的那个 x 的左边/右边都应有偶数个数。

而 N 为偶数时这是不可能办到的,即 N 为偶数时先手一开始只能选择最左边/最右边。

我们接下来考虑 N 为奇数。

此时流程变为:"先手取走一个偶数位置的数" -> "后手选择左边/右边,先手取走偶数位置的数,后手取走奇数位置的数" -> "迭代到区间的子问题" -> ... -> "先手取走区间内奇数位置的数(取走最左边/最右边的数),后手取走偶数位置的数"。

假如最后奇数位置上的数在区间 [l, r] 内,那么先手取走的数应是 "[1...l-1] 中的偶数位置" + "[l...r] 中的奇数位置" + "[r+1...N] 的偶数位置"。

不妨看成先选择全部偶数位置的数,然后选择一个区间 [l, r] 将其奇偶位置的选择状况反转。

先手需要最大化 [l, r] 中奇数位置的和 - 偶数位置的和,可以通过一些处理写成前缀和 s[r] - s[l-1] 的形式。

考虑一下二分答案:假如 s[r] - s[l-1] >= x,我们就可以知道哪些区间是合法。

可以通过手玩发现如果有些合法区间首尾相接,即存在 [l1, r1], [l2, r2], ..., [lk, rk] 使得 \(r_i + 1 = l_{i+1} - 1\),那么先手就可以最终落到某一个区间中,视为检验成功

归纳法即可证。

怎么快速检验呢?可以使用 dp。记 dp[i](此处默认 i 为偶数)表示 [1, i] 是否能划分成若干合法区间,则枚举 j < i 且 dp[j] 为真,如果有 s[i-1] - s[j] >= x 即可转移。

我们可以维护 dp[j] 为真的 min{s[j]} 来方便实现转移,这样一来甚至连 dp 都不存下来。

@accepted code@

#include <cstdio>
#include <algorithm>
using namespace std; const int MAXN = 300000;
const int INF = (1 << 30); int s[2], sum[MAXN + 5], a[MAXN + 5], N;
bool check(int x) {
int k = 0;
for(int i=2;i<=N;i+=2) {
if( sum[i-1] - k >= x )
k = min(k, sum[i]);
}
return sum[N] - k >= x;
} int main() {
scanf("%d", &N);
for(int i=1;i<=N;i++)
scanf("%d", &a[i]), s[i & 1] += a[i];
if( N % 2 == 0 )
printf("%d %d\n", max(s[0], s[1]), min(s[0], s[1]));
else {
for(int i=1;i<=N;i++) sum[i] = sum[i-1] + (i & 1 ? a[i] : -a[i]);
int le = 0, ri = s[0] + s[1];
while( le < ri ) {
int mid = (le + ri + 1) >> 1;
if( check(mid) ) le = mid;
else ri = mid - 1;
}
printf("%d %d\n", s[0] + le, s[1] - le);
}
}

@details@

我才不会说我一开始想到了二分答案随后就把它叉掉了。

最后写了个神奇的线段树做法,发现过不了,然后把它叉掉过后又想起了二分答案其实可以做。

感觉脑子需要修理一下,最近短路的现象太频繁了。

@atcoder - AGC026F@ Manju Game的更多相关文章

  1. p_b_p_b 杂题选讲

    [ARC119F] AtCoder Express 3 [ARC117F] Gateau 考虑二分答案,对前缀和建差分约束 \(\text{check}\) ,但是用 \(\text{spfa}\) ...

  2. Atcoder Grand Contest 026 (AGC026) F - Manju Game 博弈,动态规划

    原文链接www.cnblogs.com/zhouzhendong/AGC026F.html 前言 太久没有发博客了,前来水一发. 题解 不妨设先手是 A,后手是 B.定义 \(i\) 为奇数时,\(a ...

  3. AtCoder Regular Contest 061

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

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

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

  5. AtCoder Regular Contest 082

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

  6. AtCoder Regular Contest 069 D

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

  7. AtCoder Regular Contest 076

    在湖蓝跟衡水大佬们打的第二场atcoder,不知不觉一星期都过去了. 任意门 C - Reconciled? 题意:n只猫,m只狗排队,猫与猫之间,狗与狗之间是不同的,同种动物不能相邻排,问有多少种方 ...

  8. AtCoder Grand Contest 016

    在雅礼和衡水的dalao们打了一场atcoder 然而窝好菜啊…… A - Shrinking 题意:定义一次操作为将长度为n的字符串变成长度n-1的字符串,且变化后第i个字母为变化前第i 或 i+1 ...

  9. AtCoder Beginner Contest 069【A,水,B,水,C,数学,D,暴力】

    A - K-City Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement In K-city, ...

随机推荐

  1. ThinkPHP6.0 容器和依赖注入

    ThinkPHP6.0 容器和依赖注入 分为如下两部分: 依赖注入 容器 依赖注入 依赖注入其实本质上是指对类的依赖通过构造器完成自动注入: 在控制器架构方法和操作和方法中一旦对参数进行对象类型约束则 ...

  2. poj3683 2-SAT 同上一道

    Priest John's Busiest Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10151   Accep ...

  3. 解决iframe重定向让父级页面跳转

    原文:http://www.jb51.net/article/40583.htm 有内嵌iframe的页面,当session过期时,点击连接重定向后的跳转会在iframe中跳转,在登录页面中加入下面的 ...

  4. 还不会K8S吗?先从kubeadm开始吧

    目录 1. 准备工作 1.1 机器准备 1.2 系统配置 1.2.1 主机名及域名解析 1.2.2 免密登录 1.2.3 配置yum源 1.2.4 安装必要依赖包 1.2.5 关闭防火墙.SELinu ...

  5. c# 优化代码的一些规则——const 和 readonly[二]

    前言 在c# 的世界中,在初学的时候,可能很难区分readonly 和 const,两者都是不可修改. 看到这两个单词,我们想的是,最多他们的区别也不会太大.然后事实却出乎我们的意料. 正文 这两个声 ...

  6. Redis学习笔记(2)

    一.配置文件(部分) 1. UNITS(单位) 数据单位 2. INCLUDES(包含) 可以包含其他配置文件,而redis.conf作为总的配置文件 3. NETWORK(网络配置) -网络端口的绑 ...

  7. Qt版本中国象棋开发(二)

    实现功能:棋盘绘制 核心函数: void paintEvent(QPaintEvent *); //QWidget自带的虚函数,重写后使用 QPainter 类来绘制图形 QPainter paint ...

  8. [优文翻译]003.你应避免的移动开发APP的5个细节(5 Things to Avoid while Developing Your Next Mobile App)

    导读:本文是从<5 Things to Avoid while Developing Your Next Mobile App>这篇文章翻译而来 智能手机的普及带动了大批移动应用的诞生,这 ...

  9. 在线编写复杂的数学公式--EdrawMath

    网址: EdrawMath , 非常好用

  10. 用java方式实现快速排序

    一.基本思想 快速排序采用分治的策略,具体如下:选择一个关键值作为基准值,找到一个元素小于比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一般是无序的).一般选用序列第一个元素作为基准 ...