原文链接 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已经偏难,而后一部分的优化对思维能力和细节处理能力的要求,是在博主目前能力之上的,也体现了算法优化的一些重要思路。

【做题】CSA49F - Card Collecting Game——思维&dp的更多相关文章

  1. 【做题】ECFinal2018 J - Philosophical … Balance——dp

    原文链接 https://www.cnblogs.com/cly-none/p/ECFINAL2018J.html 题意:给出一个长度为\(n\)的字符串\(s\),要求给\(s\)的每个后缀\(s[ ...

  2. 【做题】CF177G2. Fibonacci Strings——思维+数列

    题意:定义斐波那契字符串为: $f_1 = $ "a" \(f_2 =\) "b" \(f_n = f_{n-1} + f_{n-2}, \, n > 2 ...

  3. 【做题】arc070_f-HonestOrUnkind——交互+巧妙思维

    做的第一道交互题-- 首先,有解的一个必要条件是\(a>b\).否则,即当\(a<=b\)时,可以有\(a\)个unkind的人假装自己就是那\(a\)个honest的人.(彼此之间都说是 ...

  4. 【做题】CF285E. Positions in Permutations——dp+容斥

    题意:求所有长度为\(n\)的排列\(p\)中,有多少个满足:对于所有\(i \,(1 \leq i \leq n)\),其中恰好有\(k\)个满足\(|p_i - i| = 1\).答案对\(10^ ...

  5. DP 做题记录 II.

    里面会有一些数据结构优化 DP 的题目(如 XI.),以及普通 DP. *I. P3643 [APIO2016]划艇 题意简述:给出序列 \(a_i,b_i\),求出有多少序列 \(c_i\) 满足 ...

  6. 【做题】spoj4060 A game with probability——dp

    赛前做题时忽然发现自己概率博弈类dp很弱,心好慌.(获胜概率或最优解期望) 于是就做了这道题,续了特别久. 一开始列dp式子的时候就花了很长时间,首先搞错了两次,然后忘记了根据上一轮dp值直接确定选什 ...

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

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

  8. DP 优化方法大杂烩 & 做题记录 I.

    标 * 的是推荐阅读的部分 / 做的题目. 1. 动态 DP(DDP)算法简介 动态动态规划. 以 P4719 为例讲一讲 ddp: 1.1. 树剖解法 如果没有修改操作,那么可以设计出 DP 方案 ...

  9. DP【洛谷P1704】 寻找最优美做题曲线

    [洛谷P1704] 寻找最优美做题曲线 题目背景 nodgd是一个喜欢写程序的同学,前不久(好像还是有点久了)洛谷OJ横空出世,nodgd同学当然第一时间来到洛谷OJ刷题.于是发生了一系列有趣的事情, ...

随机推荐

  1. python基础3 条件判断 if嵌套

    if单向判断: stonenumber=6#为宝石数量赋值 if stonenumber>=6: #条件:如果你拥有的宝石数量大于等于6个 print('你拥有了毁灭宇宙的力量') #结果:显示 ...

  2. net-tools与iproute2

    net-tools与iproute2 我们知道redhat系列发行版7x版本中最小化安装是没有net-tools工具包的,默认使用iproute2工具包,最直观的感受是ifconfig命令被ip命令所 ...

  3. Linux环境下虚拟环境virtualenv安装和使用

    virtualenv用于创建独立的Python环境,多个Python相互独立,互不影响,它能够: 1. 在没有权限的情况下安装新套件 2. 不同应用可以使用不同的套件版本 3. 套件升级不影响其他应用 ...

  4. hystrix参数使用方法

    hystrix+feign+ribbon,但是可能很多人都知道hystrix还有线程隔离,信号量隔离,等等各种参数配置,在这几就记录下hystrix的参数, 一.hystrix参数使用方法 通过注解@ ...

  5. nfs 共享目录

    依赖的包 yum -y install nfs-utils vim /etc/exports /data/test_nfs 10.125.37.12/16(rw,sync,no_root_squash ...

  6. 白话skynet第一篇

    当你走过一个坐在自己店门前的杂货商面前.走过一个吸着烟斗的守门人面前,走过一个马车夫面前时,请你给我描绘一下这个杂货商.守门人和马车夫,他们的姿态,他们的外貌,要用画家那样的细节描绘出他们的精神本质, ...

  7. IMU 标定 | 工业界和学术界有什么不同?

    点击"计算机视觉life"关注,置顶更快接收消息! 由于格式问题最好在公众号上观看<IMU 标定-工业界和学术界有什么不同?> 本文主要介绍了IMU基本结构原理和误差的 ...

  8. h5页面适配小结

    大概是去年的7月想写这个内容去加深自己的理解.现在终于回来补上这篇入门小结了. 1.问题描述 适配的目标:在不同尺寸的手机设备上,页面“相对性的达到合理的展示(自适应)”或者“保持统一效果的等比缩放( ...

  9. Oracle中对XMLType的简单操作(extract、extractvalue...)

    Oracle中对XMLType的简单操作(extract.extractvalue...)    1.下面先创建一个名未test.xml的配置文件. <?xml version="1. ...

  10. django中如何实现分页功能

    1.在html页面中导入js文件和css文件 <link rel="stylesheet" href="../../../static/css/jquery.pag ...