【做题】CSA49F - Card Collecting Game——思维dp
原文链接 https://www.cnblogs.com/cly-none/p/CSA49F.html
题意:Alice和Bob在玩游戏。有\(n\)种卡牌,每种卡牌有\(b_i\)张,保证\(\sum b_i\)为偶数。现在,Alice要把所有卡牌任意平分为2份(仅要求每份卡牌数为\(\frac {\sum b_i} {2}\)),并对每份分别进行一次游戏。第一次游戏由Alice先手,第二次由Bob先手。
每次游戏中,Alice和Bob会轮流取走一张卡牌直到取尽。设最后Alice有\(n_i\)张第\(i\)种牌,那么她会得到\(\left\lfloor \frac {n_i} {a_i} \right\rfloor c_i\)的分数。一次游戏的得分是Alice从每种牌得到的分数总和。
现在,Alice想要最大化两次游戏的得分总和,Bob则想最小化。求出在两人都采取最优决策时的得分总和。
\(n \leq 2\times 10^3, \ \sum a_i \leq 2 \times 10^3, \ \sum b_i \leq 5\times 10^5, \ c_i \geq 0\)
先考虑如何计算一次游戏的得分。
首先,因为是轮流取,故对于每\(2a_i\)张卡牌\(i\),都能产生\(c_i\)的分数。因此,我们可以先考虑这一部分的贡献,然后将所有\(n_i\)对\(2a_i\)取模。
接下来,考虑如果\(n_i < 2a_i - 1\),那么只要Bob跟着Alice取,Alice就得不到这个\(c_i\)。当\(n_i = 2a_i - 1\)时,先手就能恰好取到\(a_i\)张牌,但先后手顺序会交换。
因此,对于剩下来的卡牌,我们忽略\(n_i < 2a_i - 1\)的,并对剩下的按\(c_i\)从大到小排序。那么,若Alice先手,就能得到\(\sum_{2 \nmid i} c_i\)的分数;否则就是\(\sum_{2 | i} c_i\)。
那么,我们就能得到一个dp的做法。以\(c_i\)为关键字排序后,设\(dp[i,j,a,b]\)表示当前处理了前\(i\)种卡牌,第一份已经有\(j\)张卡牌,且第一份有\(a\)种\(n_i\)对\(2a_i\)取模后是\(2a_i-1\)的卡牌,第二份有\(b\)种。注意到只要记录\(a\)和\(b\)的奇偶性就可以了。暴力转移,则这个dp的复杂度是\(O((\sum b_i)^2)\)。
但这样还不足以解决本题。考虑\(\sum a_i\)比较小,故我们要从这个角度来优化dp。
先注意到两点,一是我们在转移时,产生的贡献只和放到第一份的数量对\(2a_i\)取模的值有关;二是dp状态中最庞大的\(j\),最后只是用来确定第一份的数量等于\(\frac {\sum b_i} {2}\)的。于是我们考虑对\(j\)进行优化,目的是在转移时,只用枚举放在第一份的数量对\(2a_i\)取模的值。
于是我们把第一份卡牌分为两个部分,一部分是所有\(n_i\)对\(2a_i\)取模后的结果,则另一部分的卡牌总数就是\(\sum_{i} 2a_ik_i\)的形式。要保证第一份的卡牌总数为一个固定值,我们就要求出\(\sum_{i} 2a_i k_i\)的能表示出哪些数。
先考虑\(k_i\)的取值范围。设\(n_i \mod 2a_i = r_i\),那么\(k_i\)就是在\(\left[ 0, \left\lfloor \frac {b_i - r_i} {2a_i} \right\rfloor \right]\)之间的整数。但\(\left\lfloor \frac {b_i - r_i} {2a_i} \right\rfloor\)有两种取值:在\(r_i \leq b_i \mod 2a_i\)时,为\(\left\lfloor \frac {b_i} {2a_i} \right\rfloor\);否则是\(\left\lfloor \frac {b_i} {2a_i} \right\rfloor - 1\)。于是我们不妨就令\(k_i\)的上界为\(\left\lfloor \frac {b_i} {2a_i} \right\rfloor - 1\),当\(r_i \leq b_i\)的时候,把多出来的那个\(2a_i\)算在第一部分里就可以了。
剩下就是一个背包问题。注意到我们可以把\(a_i\)相等的数放在一起计算,而\(a_i\)只有$ \sqrt {\sum a_i}\(种取值,因此这个问题的复杂度是\)O(\sqrt {\sum a_i} (\sum b_i))$的。
总结一下,第一部分的处理和\(O((\sum b_i)^2)\)的算法差不多,但这一部分的复杂度是\(O((\sum a_i)^2)\)的。第二部分的背包,复杂度为\(O(\sqrt {\sum a_i} (\sum b_i))\)。
于是时间复杂度为\(O((\sum a_i)^2 + \sqrt {\sum a_i} (\sum b_i))\)。
#include <bits/stdc++.h>
using namespace std;
const int A = 2010, B = 500010, N = 2010;
int dp[2][A << 2][2][2], bag[B], n, num[A], p, sa, sb, ans;
struct data {int a,b,c;bool operator < (const data& x) const {return c > x.c;}
} dat[N];
inline void ckmx(int& x,int y) {x = x < y ? y : x;
}
int main() {scanf("%d",&n);for (int i = 1 ; i <= n ; ++ i)scanf("%d%d%d",&dat[i].a, &dat[i].b, &dat[i].c);sort(dat+1,dat+n+1);for (int i = 1 ; i <= n ; ++ i) {if (dat[i].b / (dat[i].a << 1) - 1 > 0)num[dat[i].a] += dat[i].b / (dat[i].a << 1) - 1;sa += dat[i].a;sb += dat[i].b;}p = 1;memset(dp,-1,sizeof dp);dp[0][0][0][0] = 0;for (int i = 1, sum = 0 ; i <= n ; ++ i, p ^= 1) {memset(dp[p],-1,sizeof dp[p]);for (int j = 0 ; j <= (sum << 2) ; ++ j)for (int a = 0 ; a < 2 ; ++ a)for (int b = 0 ; b < 2 ; ++ b) {if (dp[p^1][j][a][b] == -1) continue;for (int k = 0 ; k < 2 * dat[i].a && k <= dat[i].b ; ++ k) {int tmp = (dat[i].b - k) / (dat[i].a << 1), na = a, nb = b;if (k == 2 * dat[i].a - 1) {if (!na) tmp ++;na ^= 1;}if ((dat[i].b - k) % (dat[i].a << 1) == (dat[i].a << 1) - 1) {if (nb) tmp ++;nb ^= 1;}tmp = tmp * dat[i].c;ckmx(dp[p][j + k][na][nb], dp[p^1][j][a][b] + tmp);if (dat[i].b >= 2 * dat[i].a && k <= dat[i].b % (dat[i].a << 1))ckmx(dp[p][j + k + 2 * dat[i].a][na][nb], dp[p^1][j][a][b] + tmp);}}sum += dat[i].a;}bag[0] = 1;for (int i = 1 ; i < A ; ++ i) {if (!num[i]) continue;for (int j = 0 ; j <= sb ; ++ j) {if (bag[j]) bag[j] = 0;else {bag[j] = -1;if (j >= 2 * i) {if (bag[j - 2 * i] != -1)bag[j] = bag[j - 2 * i] + 1;}}}for (int j = 0 ; j <= sb ; ++ j)if (bag[j] == -1) bag[j] = 0;else if (bag[j] <= num[i]) bag[j] = 1;else bag[j] = 0;}p ^= 1;for (int i = 0 ; i <= (sa << 2) && i <= (sb >> 1) ; ++ i)for (int a = 0 ; a < 2 ; ++ a)for (int b = 0 ; b < 2 ; ++ b) {if (dp[p][i][a][b] == -1) continue;if (bag[(sb >> 1) - i]) ans = max(ans, dp[p][i][a][b]);}printf("%d\n",ans);return 0;
}
小结:这个问题相当有难度。得到\(O((\sum b_i)^2)\)的dp已经偏难,而后一部分的优化对思维能力和细节处理能力的要求,是在博主目前能力之上的,也体现了算法优化的一些重要思路。
转载于:https://www.cnblogs.com/cly-none/p/CSA49F.html
【做题】CSA49F - Card Collecting Game——思维dp相关推荐
- 概率期望题(期望 DP)做题记录
概率期望题(期望 DP)做题记录 P3830 [SHOI2012]随机树 难点在于第二问:生成树的期望深度. 不 wei zhuo 捏,设 \(dp_{i,j}\) 表示已经有了 \(i\) 个叶子结 ...
- 数数题(计数类 DP)做题记录
数数题(计数类 DP)做题记录 CF1657E Star MST 我们称张无向完全图是美丽的当且仅当:所有和 \(1\) 相连的边的边权之和等于这张完全图的最小生成树的边权之和. 完全图点数为 \(n ...
- bzoj5108 [CodePlus2017]可做题 位运算dp+离散
[CodePlus2017]可做题 Time Limit: 10 Sec Memory Limit: 512 MB Submit: 87 Solved: 63 [Submit][Status][D ...
- 创业需要的学习能力不是读书考试做题也不是所谓的思维格局
创业需要的学习能力不是读书考试做题也不是所谓的思维格局,它是一个感知-观察-实践-复盘-提升的能力. 为什么说思维格局没有什么用,感知能力最重要最基础. 是这样的,人不能脱离自己现有的基础,立刻就上月 ...
- dp做题想法(满纸荒唐言)
又一周很快过去了,说实话这周做题不太多,有舍友过生日的筹划庆祝,也有周六的班级郊游聚会,当然周六可差点把我冻死,天有不测风云吧,之前也没想到会这么冷.当然这些都不是做的少的理由,还是懒吧,害怕遇到困难 ...
- 洛谷P3146 区间dp做题笔记
不是题解,不是题解,不是题解,纯属个人笔记,不知所言. 传送门:P3146 问:什么时候才能写的一手漂亮的dp? 答:夜深人静之时,魂归故里之日. 此题是一道基础的区间dp的题,看完题解犹豫片刻,之后 ...
- Regional 做题记录 (50/50)
写在前面 博主深感自己太弱了QAQ 于是有了一个刷水的想法,Regional的题目还是有很多考查思维的题目,所以这次是乱做50道思考题,可能会顺带做一些水题,这些题的简要题解会写到这篇博文里面,希望能 ...
- web做题记录(buuoj,jarvis,攻防世界,bugku,hackme)
web做题笔记 文章目录 web做题笔记 buuoj easy_tornado 随便注 warmup easysql 高明的黑客 jarvisoj re? flag在管理员手上 api调用 chopp ...
- NOIP2016考前做题(口胡)记录
NOIP以前可能会持续更新 写在前面 NOIP好像马上就要到了,感觉在校内训练里面经常被虐有一种要滚粗的感觉(雾.不管是普及组还是提高组,我都参加了好几年了,结果一个省一都没有,今年如果还没有的话感觉 ...
最新文章
- LiteSeg: 一种用于语义分割的轻量级ConvNet
- 让Java程序只运行一个实例
- 《关系营销2.0——社交网络时代的营销之道》一从单向沟通转向多方沟通
- 从源码角度看Android系统init进程启动过程
- Boost:bind绑定右值的测试程序
- 现金贷平台倒闭后,借的钱是否可以不还?
- java变量作用域Scope
- VMware安装Centos7后有线线缆被拔出
- ViT(Vision Transformer)学习
- Intent各种flag解析。
- python官网安装程序的功能和特点_python介绍与安装(一)
- Python学习:Mysql(二)
- LOADRUNNER居于HTTP协议函数使用
- 基于TensorRT量化部署RepVGG模型
- 目前最常用的计算机机箱类型为_2016年秋计算机基础理论题 答案解析
- 阿里云DataV数据过滤器取Value值大于等于25的数据(1)
- H3C用户入网配置(radius、domain、802.1x)
- centos7安装boost记录
- OLS最小二乘法回归模型
- 2022骨传导蓝牙耳机推荐,最好用的几款骨传导耳机
热门文章
- HDU 6168 Numbers 思维 水题
- 使用NUget发布自己的dll(转)
- js new Date()
- php 逻辑与运算符使用说明
- Linux内核学习笔记五——中断推后处理机制
- 错误:The project was not built due to Unparsed aapt error(s)
- android的应用组件,跟我学android-Android应用基本组件介绍(五)
- 数据科学入门与实战:玩转pandas之四
- hdp对应hadoop的版本_好程序员大数据学习路线分享hadoop的知识总结
- android 屏幕旋转流程,android自动屏幕旋转流程分析.doc