题干:

You may have heard of the pie rule before. It states that if two people wish to fairly share a slice of pie, one person should cut the slice in half, and the other person should choose who gets which slice. Alice and Bob have many slices of pie, and rather than cutting the slices in half, each individual slice will be eaten by just one person.

The way Alice and Bob decide who eats each slice is as follows. First, the order in which the pies are to be handed out is decided. There is a special token called the "decider" token, initially held by Bob. Until all the pie is handed out, whoever has the decider token will give the next slice of pie to one of the participants, and the decider token to the other participant. They continue until no slices of pie are left.

All of the slices are of excellent quality, so each participant obviously wants to maximize the total amount of pie they get to eat. Assuming both players make their decisions optimally, how much pie will each participant receive?

Input

Input will begin with an integer N (1 ≤ N ≤ 50), the number of slices of pie.

Following this is a line with N integers indicating the sizes of the slices (each between 1 and 100000, inclusive), in the order in which they must be handed out.

Output

Print two integers. First, the sum of the sizes of slices eaten by Alice, then the sum of the sizes of the slices eaten by Bob, assuming both players make their decisions optimally.

Examples

Input

3
141 592 653

Output

653 733

Input

5
10 21 10 21 10

Output

31 41

Note

In the first example, Bob takes the size 141 slice for himself and gives the decider token to Alice. Then Alice gives the size 592 slice to Bob and keeps the decider token for herself, so that she can then give the size 653 slice to herself.

题目大意:

有一个长度为N的权值数组,两个人A,B。定义一种权力X为:决定当前这个数组元素分给谁。下次权利X授予没有分得前一个元素的人。如,现在A有权力,将当前数组元素分给自己,那么下一次权力X将被B获得。如果A将数组元素分给B,那么A继续拥有这个权利。一开始权利在A手中,每个人都会采取对自己最有利的方式分配。问最后两个人各自的权值总和。

解题报告:

考虑dp求解,要明确dp的状态只与是否有令牌有关,而与令牌在谁手里无关。因为不论令牌在谁手里,那个人都会尽可能的获得最大的物品价值。

因此我们用dp[i]表示第i个物品开始分配,当前有令牌的人能获得的最大物品价值,然而因为我们只知道初始有令牌的是Bob,因此我们要逆推: dp[i] = max(dp[i + 1], sum[i + 1] - dp[i + 1] + val[i]) // max(不要当前物品, 要)

其实相当于是你如果要从前往后推的话,需要关注令牌是否是同一个人拿着的,所以麻烦很多,而逆推就简单很多,因为令牌是往后传的,我们当前是有令牌的,所以下一个令牌给谁,是我们决定的,就比较好写。

最后dp[1]就是Bob获得的价值了。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
ll dp[MAX],a[MAX],sum[MAX];
int main()
{int n;cin>>n;for(int i = 1; i<=n; i++) scanf("%lld",a+i);for(int i = n; i>=1; i--) sum[i] = sum[i+1] + a[i];for(int i = n; i>=1; i--) {dp[i] = max(dp[i+1],a[i] + (sum[i+1] - dp[i+1]));//不选,选 }printf("%lld %lld\n",sum[1] - dp[1],dp[1]);return 0 ;}

错误代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
ll a[MAX],sum[MAX];
ll dp[MAX][2][2];//dp[i][j][k]代表第i个数并且第i个选没选0/1,令牌在 0/1(Bob)手里的最大值 ,Bob获得的最大值
int main()
{int n;cin>>n;for(int i = 1; i<=n; i++) scanf("%lld",a+i);for(int i = 1; i<=n; i++) sum[i] = sum[i-1] + a[i];dp[1][1][1] = a[1];dp[1][0][1] = 0;for(int i = 2; i<=n; i++) {dp[i][0][0] = a[i] + max(dp[i-1][1][1] , dp[i-1][0][0]);//sum[i-1] - min(dp[i-1][1][1] , dp[i-1][0][0]);dp[i][0][1] = max(dp[i-1][1][0] , dp[i-1][0][1]);dp[i][1][0] = dp[i][0][0];dp[i][1][1] = dp[i][0][1] + a[i];}ll maxx = 0;maxx = max(maxx,dp[n][0][0]);maxx = max(maxx,dp[n][0][1]);maxx = max(maxx,dp[n][1][0]);maxx = max(maxx,dp[n][1][1]);printf("%lld %lld\n",sum[n] - maxx,maxx);return 0 ;}
//适用于:可以选择要或者不要,但是不要的话不会把分数给对方  的方法。
//  for(int i = 2; i<=n; i++) {
//      dp[i][0][0] = max(dp[i-1][1][1] , dp[i-1][0][0]);//sum[i-1] - min(dp[i-1][1][1] , dp[i-1][0][0]);
//
//      dp[i][0][1] = max(dp[i-1][1][0] , dp[i-1][0][1]);
//      dp[i][1][0] = dp[i][0][0];
//      dp[i][1][1] = dp[i][0][1] + a[i];
//  }

想到这个状态感觉可以就开始写了, 但是有个问题啊,,这是个博弈dp,也就是说你不能只顾着Bob,所以这样dp是错误的,因为对方也是用的最优决策你要知道这一点,所以就不太对。所以对于这种博弈dp,我们需要关注的是令牌,因为谁拿着令牌,谁就希望得到最优解。所以我们应该直接设定状态为dp[i]为拿着令牌的人第i轮选择到最后可以得到的最优解。

为什么倒着呢?因为这是求最优解问题,就跟数塔一样,先考虑最后一步决策,然后倒着推。如果是计数,那就一般正着写。

(其实貌似也是可以写的?就是比较麻烦,你考虑令牌不在Bob手里的时候求的是Bob拿到的最小值 就行了吧?)

改了改但还是放弃了、、、

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
ll a[MAX],sum[MAX];
ll dp[MAX][2][2];//dp[i][j][k]代表第i个数并且第i个选没选0/1,令牌在 0/1(Bob)手里的最大值 ,Bob获得的最大值
int main()
{int n;cin>>n;for(int i = 1; i<=n; i++) scanf("%lld",a+i);for(int i = 1; i<=n; i++) sum[i] = sum[i-1] + a[i];dp[1][1][1] = a[1];dp[1][0][1] = 0;for(int i = 2; i<=n; i++) {dp[i][0][0] = a[i] + sum[i-1]/*sum[i]*/ - max(sum[i-1] - dp[i-1][1][1] , sum[i-1] - dp[i-1][0][0]);//sum[i-1] - min(dp[i-1][1][1] , dp[i-1][0][0]);dp[i][0][1] = max(dp[i-1][1][0] , dp[i-1][0][1]);dp[i][1][0] = dp[i][0][0] - a[i];dp[i][1][1] = dp[i][0][1] + a[i];}ll maxx = 0;maxx = max(maxx,dp[n][0][0]);maxx = max(maxx,dp[n][0][1]);maxx = max(maxx,dp[n][1][0]);maxx = max(maxx,dp[n][1][1]);printf("%lld %lld\n",sum[n] - maxx,maxx);return 0 ;}
/*
3
10 20 40
30 40
*/

*【CodeForces - 859C 】Pie Rules (博弈dp,时光倒流)相关推荐

  1. Codeforces 859C - Pie Rules

    859C - Pie Rules 思路: dp 我们知道无论谁拿到decider token他拿不拿蛋糕都是确定的,都是使自己最优的结果. 于是 定义状态:dp[i]表示到第i个位置拿到decider ...

  2. CodeForces - 859C Pie Rules(dp+博弈)

    题目链接:点击查看 题目大意:给出n个馅饼,现在给出一个令牌,规定持有令牌的人可以选择当前的馅饼给谁,然后下一轮令牌给没有拿到馅饼的人,如此往复,一开始鲍勃拿着令牌,问最后两人能吃到多少馅饼,两人肯定 ...

  3. 时光倒流:业务支撑那些事(四)

    时光倒流:业务支撑那些事(四)文 | 宁宇 手中有粮,心中不慌.靠这套全新的计费结算系统,支撑着移动电话的迅猛发展,这种局面一直延续到2000年. 2000年中,中国移动总部已经成立,当时的名字叫做& ...

  4. 有些错误,即便时光倒流也无法弥补——《时光幻境》

    当我们追溯独立游戏的起源,就会发现其实独立游戏已经有很长的历史了,早在九十年代就有独立游戏开发者或团队,截止到目前独立游戏已有将近三十年的历史.之所以要在这里提独立游戏的历史,是因为今天说的这款游戏, ...

  5. git branch 为什么会进入编辑状态_Git很难,搞砸很容易,好在有神奇命令让时光倒流...

    Git很难,搞砸很容易,更糟糕的是搞砸了还不清楚什么问题. 虽然Git文档很全面,但不清楚什么问题,不知道问题名称,连搜索答案都无从下手.国外小哥也有遇到这些问题,因此搞了个 ohshigit 的网站 ...

  6. 天池 在线编程 双向取数(博弈DP)

    文章目录 1. 题目 2. 解题 1. 题目 https://tianchi.aliyun.com/oj/245679029019779851/254275128279634585 有一个长度为n的数 ...

  7. LeetCode 1690. 石子游戏 VII(博弈DP)

    文章目录 1. 题目 2. 解题 1. 题目 石子游戏中,爱丽丝和鲍勃轮流进行自己的回合,爱丽丝先开始 . 有 n 块石子排成一排.每个玩家的回合中,可以从行中 移除 最左边的石头或最右边的石头,并获 ...

  8. LeetCode 486. 预测赢家(博弈DP)

    文章目录 1. 题目 2. 解题 1. 题目 给定一个表示分数的非负整数数组. 玩家 1 从数组任意一端拿取一个分数,随后玩家 2 继续从剩余数组任意一端拿取分数,然后玩家 1 拿,-- . 每次一个 ...

  9. 时光倒流-第12届蓝桥杯Scratch选拔赛真题精选

    [导读]:超平老师计划推出Scratch蓝桥杯真题解析100讲,这是超平老师解读Scratch蓝桥真题系列的第88讲. 蓝桥杯选拔赛每一届都要举行4~5次,和省赛.国赛相比,题目要简单不少,再加上篇幅 ...

最新文章

  1. Oracle11g_同义词
  2. C++入门教程,全套C++基础教程(已更新完毕)
  3. 用matlab求残余误差,matlab在测量误差分析中的应用
  4. Github CodeSpaces 使用及定制化
  5. java 设计模式_Java设计模式的常见应用场景
  6. numpy将bool值转换成数值
  7. Windows下Git客户端的安装及配置
  8. 更喜欢使用Stream到byte[]
  9. 安装SQL2005示例数据库
  10. mysql 汉字拼音怎么获得_mysql汉字拼音取法
  11. orcad导出BOM
  12. FileZilla传输文件乱码的解决方案
  13. Linux系统下的文件和文件夹相关操作(创建/删除/修改权限)
  14. 求知以解惑 温故而知新 ——重读哥德尔之一(开篇)
  15. C++ 多种取整函数的使用和区别: ceil() floor() round() trunc() rint() nearbyint()
  16. 量化投资学习——关于XTP交易柜台
  17. 视频教程-21天通关Python(课+书,含邮寄)-Python
  18. 前沿 | 国际可视化盛会PacificVis2017的十个精彩案例
  19. 正射影像地理坐标转像素坐标c语言,Landsat 8影像像元地理坐标计算.pdf
  20. 城市轨道交通联锁试验方法介绍

热门文章

  1. 单节点hadoop部署成功
  2. 641. Design Circular Deque
  3. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第23篇]写一个实现蒙哥马利算法的C程序
  4. [Leedcode][JAVA][第560题][和为K的子数组][Hashmap][数组]
  5. [Java]中[this][super]用法总结
  6. druid 非对称加密_springboot配置文件中mysql的密码进行加密
  7. git merge用法_常用命令之git操作(进阶篇)
  8. pb mysql 中文乱码_解决springmvc+mybatis+mysql中文乱码问题
  9. Tidb集群加mysql_TiDB - 快速入门,集群搭建
  10. 前台文件_欧木瑾怎么定制办公前台?