题目传送门:CSU 2095:Sweet War

题目大意:皮皮王和嘤嘤怪是好朋友,一天她俩出去玩,皮皮王发现了一个一端开口的玻璃管(大概试管那样的)。玻璃管里有好多巧克力豆一个挨着一个地排着。皮皮王和嘤嘤怪给每个巧克力豆估算了一个美味值s[i]和营养值r[i],她俩都想吃到的巧克力的美味值总和最大(巧克力从开口的一端向封闭的一端依次编号1,2,...,n,只能按顺序一个一个地吃)。于是,她俩就打算玩游戏,两个人轮流进行操作,规则如下:

(1)每个人有一个初始饱食度A,B

(2)每个人轮到自己的时候有两种操作:吃了巧克力豆(饱食度增加那个巧克力豆的营养值),或者直接pass(饱食度下降1,饱食度为0不能pass)

(3)皮皮王先手,皮皮王和嘤嘤怪都特别聪明,能够保证自己每一步都是最优的~

(4)巧克力豆吃完游戏结束

问:皮皮王和嘤嘤怪吃到的巧克力豆的美味度总和

数据范围:0<=A,B,r[i]<=1e9,1<=N<=150,0<=s[i] and ∑s[i] <= 150

分析:

额,这一题我是看VJ上ACMer分享的代码的——菜到做不出来。。写博客的目的是发现这一题DP思路很奇妙啊,别人代码看一遍,醍醐灌顶。我称之为“指鹿为马DP法”(当然,这是我瞎编的词)——通常,我们一个dp数组,求出来之后,其中某一个或者多个值会是我们需要的最终结果,或者再对它们进行少量运算得到最终结果。然而,这一题比较奇特的是,最终结果不是从dp值里选取,而是在dp数组的索引里面选取(就很骚~)。由于以前没做过这种题,直接印象就是觉得饱食度应该作为索引,而美味度应该作为dp值,饱食度范围是1e9,这数组根本没法开,没法做。

言归正传,首先,我们必须认清一个事实,某个人要进行pass操作时,那么前提是她的饱食度更高(由于两个人都非常聪明,那么pass必定是为了吃到下一个更优,如果想要pass的人饱食度比较低,那么另一个人也会选择pass,两个人一起消耗饱食度,饱食度低的肯定就耗不过了)。也就是说,两个人的实际饱食度我们并不关心,只关心二人饱食度的差值。现在我们以皮皮王为主角,以dp数组表示皮皮王的饱食度减去嘤嘤怪的饱食度。dp[i][j][k]表示从i开始操作直到结束,吃到j饱食度所需要的最小相对饱食度,k表示当前轮到谁进行操作了,0指代皮皮王,1指代嘤嘤怪。那么关键的来了:

                dp[i][j][0] = min(dp[i+1][max(0LL, j-s[i])][1]-r[i], max(dp[i+1][j][0]+1+r[i], 1LL));dp[i][j][1] = max(dp[i+1][j][0] + r[i], min(dp[i][j][0]-1, -1LL));

解释一波:

对于dp[i][j][0]:

(1)dp[i+1][max(0LL, j-s[i])][1]-r[i]表示皮皮王吃掉了这个豆,饱食度增加r[i],那么当前的饱食度就比下一轮低r[i],第二维的max(...)意思很明显,当然要不小于0啊~

(2)dp[i+1][j][0]+1+r[i]表示皮皮王选择了pass,那么自己需要消耗1的饱食度,嘤嘤怪吃了那个巧克力豆,饱食度增加r[i],那么相对的皮皮王饱食度降低r[i],那么皮皮王当前的相对饱食度就需要比下一轮搞1+r[i],至于max(...)就如前面所说,饱食度高的人才有资格去pass,即相对饱食度至少为1才有资格pass

(3)由于皮皮王非常聪明,她当然会在(1)和(2)里选择一个较小的去操作啊,想要以有限的饱食度达到更高的美味度,那就必然需要以更低的饱食度达到相同的美味度啊

对于dp[i][j][1]:

max()括号里的就不解释了,和上面同理,但为啥前面是min而这里是max呢?——现在轮到嘤嘤怪操作了啊,她想自己达到结果更优,当然会在吃与pass之间选择需要使dp值大的啊,这样皮皮王想吃同样的美味度,就需要更多的饱食度了。

dp求完之后,遍历dp[1][j][0],表示皮皮王从第一个开始吃,满足当前饱食度的最大的j,这就是她所能达到的最大美味度

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<vector>
#define ll long longusing namespace std;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int main()
{#ifdef AFeifreopen("in.c", "r", stdin);#endif // AFeill n, A, B;ll r[152], s[152];ll dp[152][152][2];while(~scanf("%lld%lld%lld", &n, &A, &B)){ll sum = 0;memset(dp, 0x3f, sizeof dp);for(int i = 1; i <= n; ++ i){scanf("%lld%lld", &r[i], &s[i]);sum += s[i];}dp[n+1][0][0] = dp[n+1][0][1] = -INF;for(int i = n; i; -- i){for(int j = 0; j <= sum; ++ j){dp[i][j][0] = min(dp[i+1][max(0LL, j-s[i])][1]-r[i], max(dp[i+1][j][0]+1+r[i], 1LL));dp[i][j][1] = max(dp[i+1][j][0] + r[i], min(dp[i][j][0]-1, -1LL));}}ll ans = 0;for(int i = sum; i >= 0; -- i){if(dp[1][i][0] <= A-B){ans = i;break;}}printf("%lld %lld\n", ans, sum-ans);}return 0;
}

博弈论+指鹿为马DP法(CSU 2095: Sweet War题解)相关推荐

  1. BZOJ 2281 Luogu P2490 [SDOI2011]黑白棋 (博弈论、DP计数)

    怎么SDOI2011和SDOI2019的两道题这么像啊..(虽然并不完全一样) 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?i ...

  2. 博弈论—NP图法kiki's game HDU - 2147

    题解:这一题用NP图来进行求解,分别画出 偶X奇,偶X偶,奇X奇的矩阵来找出规律来即可求出结果. NP图的画法: 博客: https://blog.csdn.net/Adusts/article/de ...

  3. BZOJ2281:[SDOI2011]黑白棋(博弈论,组合数学,DP)

    Description 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小 ...

  4. Financiers Game CodeForces - 737D (博弈论,区间dp)

    大意: 给定$n$元素序列, 两个人从两端轮流拿数, 每一步假设对手上次取k, 那么只能取k或k+1, 先手第一步取1或2, 直到不能拿时停止. 先手要最大化两人数字和的差, 后手要最小化, 求最后差 ...

  5. [逆向并查集+STLmap存图奇法] Connections in Galaxy War ZOJ - 3261

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261 这题 感谢bo同学大力帮助...告诉我 奇技淫巧 虽然思路蛮顺的 题 ...

  6. Codeforces Round #699 (Div. 2) F - AB Tree(贪心、树上DP)超级清晰,良心题解,看不懂来打我 ~

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Codeforces Round #699 (Div. 2) F - AB Tree Problem ...

  7. Codeforces Round #699 (Div. 2) E.Sorting Books(贪心+DP / 线段树)超高质量题解,看不懂来打我 ~

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 E - Sorting Books 一排书架上有 nnn 本书排成一排,每本书上有一个颜色 aia_i ...

  8. c++ dp 贪婪的戈尔曼题解

    1.题目: 从前有2只狗,大的叫大狗,小的叫小狗,它们2个合起来就是狗儿们,使用英语的人把它们写作Girlman,传来传去,到最后大家决定叫它们格尔曼.它们 的叫声很特别,但是它们十分吝啬它们的叫声, ...

  9. 理解至上:数位dp(ybtoj-B数计数)

    文章目录 简要 题目描述 解析 dp定义: 试填法 代码 thanks for reading! 简要 数位dp,天下第一 最重要的应该有两个: 1.状态转移式的确定 2.试填法不断往后模拟 (至今是 ...

最新文章

  1. 如何在CentOS6.2上安装并运行飞鸽传书
  2. Js - 复制 粘贴
  3. 继续努力奋斗,生活会更美好
  4. java finalize逃脱_finalize(),析构函数(finalization)
  5. APP设计灵感|高颜值时钟页面!让每一秒都过得有意义
  6. 为centos5.5添加axel插件
  7. 利用idea构建hibernate
  8. Oracle如何创建数据库
  9. 该怎么复习安徽省考计算机专业课
  10. 小程序开发之AppID获取
  11. EnvironmentNotWritableError:The current user does not have write permissions to the target...
  12. 命令行压缩工具7z.exe使用详解
  13. PHP 中的 cURL 爬虫实战基础
  14. js正则表达式验证大全及常用字符的说明
  15. 使用WPS后安装Office文档图标显示异常
  16. c# 两个日期之间的比较与两个日期相差天数计算
  17. JAVA.UTIL.ARRAYLIST 详解
  18. windows64系统下安装 redis服务 (详细)
  19. [zz]微软MSN推出全新英语学习引擎 - 英库
  20. 图片放大神器【waifu2x】瞬间解决图片模糊

热门文章

  1. socket阻塞和非阻塞有哪些影响
  2. 管理学十二(流程与制度的重要性)
  3. 基于Opencv的车距检测系统(源码&教程)
  4. 重叠社区发现-LFM算法
  5. GitHub上最火的两份Java面试小册,Star已经超百万
  6. v-for图片九宫显示
  7. Android APP如何简单快速实现控制硬件设备并实现APP签名
  8. 计算机世界英语作文,计算机(Computers)
  9. 时间序列分析 | Python实现Tsprial时间序列特征提取
  10. 前端PS切片 常用不同格式图片区别