Atcoder Grand Contest 026 (AGC026) F - Manju Game 博弈,动态规划
原文链接www.cnblogs.com/zhouzhendong/AGC026F.html
前言
太久没有发博客了,前来水一发。
题解
不妨设先手是 A,后手是 B。定义 \(i\) 为奇数时,\(a_i\) 为"奇数位上的数";\(i\) 为偶数时, \(a_i\) 为"偶数位上的数"。定义左、右两端的数分别表示 \(a_1\) 和 \(a_n\)。
考虑第一步:
首先,如果 A 取了左右某一个端点,那么他必然能取走和他取的点奇偶性相同的所有点。
然后,我们考虑 A 取了一个中间点后会发生什么:如果这个点左边和右边的剩余点数都是奇数,那么无论 B 取左还是右,取完某一边之后,问题规模缩小成另一边的情况,A 一定还是先手;否则 B 就可以取剩余点数为偶数的那一边,并成为先手。
考虑 n 为偶数的情况。
如果 A 取了一个中间点,那么一定有一边剩余奇数个,一边剩余偶数个。那么 B 一定先操作偶数个的那一边,然后获得奇数那一边的先手权,然后取最优策略。那么 A 还不如直接取偶数那一边的端点,这样做不仅取到了前一种方案能取到的,而且让 B 在另一边没有了先手选择权,一定不劣于前一种方案。
所以,当 n 为偶数时,先手能取到的最大值为 max(奇数位之和, 偶数位之和) 。
n 为奇数的情况较为复杂。
但是同理,A 不会去取一个位于奇数位的数,这样会导致两边剩余个数都为偶数,不如直接取两端。
于是,n 为奇数时,A 只有两种策略:
- 取端点,即拿走所有奇数位的数。
- 取某一个偶数位的数。此时,如果 B 取左边,那么 A 会继续获得右边的先手权;否则 A 获得左边的先手权。这个过程可以看作问题规模的缩小。
如果将第二种策略用二叉树的形式表示出来,那么 B 一定会选择某一个叶子,使得最终答案最小。
考虑先假设所有偶数位的贡献都已被 A 收取,那么 A 在一个区间执行“取端点”操作得到的收益就是这个区间的奇数位之和减去偶数位之和(注意这里的两端点一定都是奇数)。
我们要做的是找出一个叶子集合,使得对这些叶子“取端点”的收益的最小值尽量大。
考虑二分答案x,之后问题转化为是否可以删除某些偶数位上的数,使得剩下的序列中任意一个极大的连续段之和都不小于x。
考虑暴力DP,枚举右端点,然后再暴力枚举前一个划分点。时间复杂度不可接受。
由于DP信息只有“能”和“不能”,所以我们可以考虑贪心,只保留“能”的点中前缀和最小的即可。
时间复杂度 \(O(n\log \sum a_i)\)。
代码
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof x)
#define For(i,a,b) for (int i=(a);i<=(b);i++)
#define Fod(i,b,a) for (int i=(b);i>=(a);i--)
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define fi first
#define se second
#define outval(x) cerr<<#x" = "<<x<<endl
#define outtag(x) cerr<<"-----------------"#x"-----------------\n"
#define outarr(a,L,R) cerr<<#a"["<<L<<".."<<R<<"] = ";\
For(_x,L,R) cerr<<a[_x]<<" ";cerr<<endl;
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
LL read(){
LL x=0,f=0;
char ch=getchar();
while (!isdigit(ch))
f=ch=='-',ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
const int N=300005;
int n;
int a[N],s[N];
bool check(int x){
int v=0;
for (int i=1;i<n;i+=2)
if (s[i]-v>=x)
v=min(v,s[i+1]);
return s[n]-v>=x;
}
int main(){
n=read();
For(i,1,n)
a[i]=read();
if (n%2==0){
int s0=0,s1=0;
For(i,1,n)
if (i&1)
s0+=a[i];
else
s1+=a[i];
cout<<max(s0,s1)<<" "<<min(s0,s1)<<endl;
return 0;
}
For(i,1,n)
if (i&1)
s[i]=s[i-1]+a[i];
else
s[i]=s[i-1]-a[i];
int L=1,R=n*1000,mid,ans=L;
while (L<=R){
mid=(L+R)>>1;
if (check(mid))
L=mid+1,ans=mid;
else
R=mid-1;
}
For(i,1,n)
if (i%2==0)
ans+=a[i];
int s=0;
For(i,1,n)
s+=a[i];
cout<<ans<<" "<<s-ans<<endl;
return 0;
}
Atcoder Grand Contest 026 (AGC026) F - Manju Game 博弈,动态规划的更多相关文章
- AtCoder Grand Contest 026 (AGC026) E - Synchronized Subsequence 贪心 动态规划
原文链接https://www.cnblogs.com/zhouzhendong/p/AGC026E.html 题目传送门 - AGC026E 题意 给定一个长度为 $2n$ 的字符串,包含 $n$ ...
- AtCoder Grand Contest 030 (AGC030) F - Permutation and Minimum 动态规划
原文链接www.cnblogs.com/zhouzhendong/p/AGC030F.html 草率题解 对于每两个相邻位置,把他们拿出来. 如果这两个相邻位置都有确定的值,那么不管他. 然后把所有的 ...
- AtCoder Grand Contest #026 C - String Coloring
Time Limit: 3 sec / Memory Limit: 1024 MB Score : 600600 points Problem Statement You are given a st ...
- AtCoder Grand Contest 002 (AGC002) F - Leftmost Ball 动态规划 排列组合
原文链接https://www.cnblogs.com/zhouzhendong/p/AGC002F.html 题目传送门 - AGC002F 题意 给定 $n,k$ ,表示有 $n\times k$ ...
- AtCoder Grand Contest 026 D - Histogram Coloring
一列中有两个连续的元素,那么下一列只能选择选择正好相反的填色方案(因为连续的地方填色方案已经确定,其他地方也就确定了) 我们现将高度进行离散化到Has数组中,然后定义dp数组 dp[i][j] 表示前 ...
- AtCoder Grand Contest #026 B - rng_10s
Time Limit: 2 sec / Memory Limit: 1024 MB Score : 600600 points Problem Statement Ringo Mart, a conv ...
- AtCoder Grand Contest #026 A - Colorful Slimes 2
Time Limit: 2 sec / Memory Limit: 1024 MB Score : 200200 points Problem Statement Takahashi lives in ...
- AtCoder Grand Contest 017D (AGC017D) Game on Tree 博弈
原文链接https://www.cnblogs.com/zhouzhendong/p/AGC017D.html 题目传送门 - AGC017D 题意 给定一棵 n 个节点的以节点 1 为根的树. 两个 ...
- AtCoder Grand Contest 012
AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...
随机推荐
- java之struts2之ajax
1.Ajax 技术在现有开发中使用非常多,大多是做管理类型系统.在servlet中可以使用ajax.在struts2中共还可以使用servlet的方式来实现ajax. 2.案例:用户名检查 publi ...
- ADO.NET 六(DataRow DataColumn)
已经介绍了使用 SqlCommand 对象中的 ExecuteNonQuery 方法执行非查询 SQL 语句来实现对数据表的更新操作,使用 DataSet 对象也能实现相同的功能, 并且能节省数据访问 ...
- 那些年,Linus torvalds大神喷过的技术
Linus Torvalds 被认为是最伟大的程序员之一,因为他写出了使用最广泛的软件,如 Linux 内核和 Git 版本控制系统.但是他这个人经常因为讲话带有情绪,甚至是因为带有脏话的意见而饱受非 ...
- day31-python之内置函数
1.udp多线程 import socketserver class MyServer(socketserver.BaseRequestHandler): def handle(self): prin ...
- android studio 出现 Default Activity not found
1.AndroidManifest.xml <activity android:name=".activity.StartPage" android:screenOrient ...
- CRM-Modelformset
CRM-Modelformset 效果图 利用modelformset实现上面的效果: views.py文件: from user.formself.myform import RegForm, Cu ...
- C++创建和使用动态链接库
一个简单的动态链接库的生成和调用例子,太过简单,大神请绕道. 一.创建动态链接库 使用vs创建工程选择动态链接库. 在项目中创建源文件和头文件,并在文件中添加以下代码. 在头文件中添加以下代码 // ...
- Vue检测当前是否处于mock模式
Vue检测当前是否处于mock模式 1.在main.js中声明全局变量: import Vue from 'vue' /* 全局变量 */ var GLOBAL_VARIABLE = { isMock ...
- 用python实现数据库查询数据方法
哈喽,好久没来了,最近搞自动化发现了很多代码弯路,特别分享出来给能用到的朋友 因为公司业务的关系,每做一笔功能冒烟测试,我们就要对很多的数据库表中的字段进行校验,当时我就想反正总是要重复的运行这些SQ ...
- 2013.4.24 - KDD第六天
今天早上,中秋给我发了一个压缩包,里面有战德臣的课件,昨天我说我SQL没学好,他说给我发战徳臣课件,然后说我SQL不会的话可以看这个,还有两篇文 章<LDA数学八卦>以及<A Not ...