原文链接 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相关推荐

  1. 概率期望题(期望 DP)做题记录

    概率期望题(期望 DP)做题记录 P3830 [SHOI2012]随机树 难点在于第二问:生成树的期望深度. 不 wei zhuo 捏,设 \(dp_{i,j}\) 表示已经有了 \(i\) 个叶子结 ...

  2. 数数题(计数类 DP)做题记录

    数数题(计数类 DP)做题记录 CF1657E Star MST 我们称张无向完全图是美丽的当且仅当:所有和 \(1\) 相连的边的边权之和等于这张完全图的最小生成树的边权之和. 完全图点数为 \(n ...

  3. bzoj5108 [CodePlus2017]可做题 位运算dp+离散

    [CodePlus2017]可做题 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 87  Solved: 63 [Submit][Status][D ...

  4. 创业需要的学习能力不是读书考试做题也不是所谓的思维格局

    创业需要的学习能力不是读书考试做题也不是所谓的思维格局,它是一个感知-观察-实践-复盘-提升的能力. 为什么说思维格局没有什么用,感知能力最重要最基础. 是这样的,人不能脱离自己现有的基础,立刻就上月 ...

  5. dp做题想法(满纸荒唐言)

    又一周很快过去了,说实话这周做题不太多,有舍友过生日的筹划庆祝,也有周六的班级郊游聚会,当然周六可差点把我冻死,天有不测风云吧,之前也没想到会这么冷.当然这些都不是做的少的理由,还是懒吧,害怕遇到困难 ...

  6. 洛谷P3146 区间dp做题笔记

    不是题解,不是题解,不是题解,纯属个人笔记,不知所言. 传送门:P3146 问:什么时候才能写的一手漂亮的dp? 答:夜深人静之时,魂归故里之日. 此题是一道基础的区间dp的题,看完题解犹豫片刻,之后 ...

  7. Regional 做题记录 (50/50)

    写在前面 博主深感自己太弱了QAQ 于是有了一个刷水的想法,Regional的题目还是有很多考查思维的题目,所以这次是乱做50道思考题,可能会顺带做一些水题,这些题的简要题解会写到这篇博文里面,希望能 ...

  8. web做题记录(buuoj,jarvis,攻防世界,bugku,hackme)

    web做题笔记 文章目录 web做题笔记 buuoj easy_tornado 随便注 warmup easysql 高明的黑客 jarvisoj re? flag在管理员手上 api调用 chopp ...

  9. NOIP2016考前做题(口胡)记录

    NOIP以前可能会持续更新 写在前面 NOIP好像马上就要到了,感觉在校内训练里面经常被虐有一种要滚粗的感觉(雾.不管是普及组还是提高组,我都参加了好几年了,结果一个省一都没有,今年如果还没有的话感觉 ...

最新文章

  1. LiteSeg: 一种用于语义分割的轻量级ConvNet
  2. 让Java程序只运行一个实例
  3. 《关系营销2.0——社交网络时代的营销之道》一从单向沟通转向多方沟通
  4. 从源码角度看Android系统init进程启动过程
  5. Boost:bind绑定右值的测试程序
  6. 现金贷平台倒闭后,借的钱是否可以不还?
  7. java变量作用域Scope
  8. VMware安装Centos7后有线线缆被拔出
  9. ViT(Vision Transformer)学习
  10. Intent各种flag解析。
  11. python官网安装程序的功能和特点_python介绍与安装(一)
  12. Python学习:Mysql(二)
  13. LOADRUNNER居于HTTP协议函数使用
  14. 基于TensorRT量化部署RepVGG模型
  15. 目前最常用的计算机机箱类型为_2016年秋计算机基础理论题 答案解析
  16. 阿里云DataV数据过滤器取Value值大于等于25的数据(1)
  17. H3C用户入网配置(radius、domain、802.1x)
  18. centos7安装boost记录
  19. OLS最小二乘法回归模型
  20. 2022骨传导蓝牙耳机推荐,最好用的几款骨传导耳机

热门文章

  1. HDU 6168 Numbers 思维 水题
  2. 使用NUget发布自己的dll(转)
  3. js new Date()
  4. php 逻辑与运算符使用说明
  5. Linux内核学习笔记五——中断推后处理机制
  6. 错误:The project was not built due to Unparsed aapt error(s)
  7. android的应用组件,跟我学android-Android应用基本组件介绍(五)
  8. 数据科学入门与实战:玩转pandas之四
  9. hdp对应hadoop的版本_好程序员大数据学习路线分享hadoop的知识总结
  10. android 屏幕旋转流程,android自动屏幕旋转流程分析.doc