「CSA49」Card Collecting Game

题目大意:有 \(n\) 种卡片,每种有 \(b_i\) 张,如果一个人集齐 \(k\) 张第 \(i\) 种卡片,那么其能获得的得分是 \(\lfloor\frac{k}{a_i}\rfloor \times c_i\) ,现在A要将所有卡片分成大小相同两堆,保证总卡片数量是偶数。A与B玩游戏,第一堆A先手轮流取,第二堆B先手轮流取,A要最大化自己的得分,B要最小化A的得分,求A能得到的最大得分。

解题思路:首先放在两堆的卡片都可以模 \(2a_i\) ,因为每 \(2a_i\) 双方必定都会各取 \(a_i\) 张取光得到 \(c_i\) 的贡献,对于剩下的部分,如果不足 \(2a_i-1\) ,那么不可能得到任何贡献 ,否则先手能得到 \(2a_i-1\) 的贡献,然后交换先后手。也就是说将每堆剩下 \(2a_i-1\) 的卡片按照 \(c_i\) 排序后,第一堆A能拿到 \(1,3,5..\) 种的贡献,第二堆A能拿到 \(2,4,6\) 种的贡献。然后就可以根据此设计 \(dp(i,j,x,y)\) 表示排完序后前 \(i\) 种卡片,放在第一堆共 \(i\) 张,当前第一堆中剩下 \(2a_i-1\) 的卡片摆了奇偶性为 \(x\) 堆,第二堆中摆了奇偶性为 \(y\) 堆,然后枚举当前这一种在第一堆种放多少计算贡献转移,复杂度是 \(O((\sum_{b_i})^2)\)。

实际上贡献只与当前该种卡片放到第一堆和第二堆中的数量除以 \(2a_i\) 的商和余数有关,商的部分无论怎样贡献都会被计算进去商-1份是常量,所以只需要考虑剩下的部分要放多少即可,但是这样的话就不能知道当前状态配上之前的常量能否凑成刚好两堆一样了,于是再对商的部分做一个多重背包判断,复杂度 \(O(\sum_{a_i}\sqrt{\sum_{b_i}}+(\sum_{a_i})^2)\)

code

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T & x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
} const int N = 4005; bitset<250005> f;
int dp[2][8005][2][2], lim[N], tot[N], yu[N], sum, ans, sumA, n; struct Node{ int a, b, c; } s[N];
inline bool cmp(Node A, Node B){ return A.c > B.c; } inline void up(int &x, int y){ if(y >= x) x = y; } int main(){
read(n);
for(int i = 1; i <= n; i++)
read(s[i].a), read(s[i].b), read(s[i].c);
sort(s + 1, s + n + 1, cmp);
for(int i = 1; i <= n; i++){
lim[i] = (s[i].b < 2 * s[i].a) ? 0 : (s[i].b / (2 * s[i].a)) - 1;
yu[i] = s[i].b - 2 * s[i].a * lim[i], ans += s[i].c * lim[i];
tot[s[i].a] += lim[i], sum += s[i].b, sumA += yu[i];
}
f[0] = 1;
for(int i = 1; i <= 2000; i++)
for(int j = 1; j <= tot[i]; j <<= 1) f |= f << (j * 2 * i);
memset(dp, -1, sizeof(dp));
dp[0][0][0][0] = 0;
for(int i = 0, o = 0; i < n; i++, o ^= 1){
memset(dp[o^1], -1, sizeof(dp[o^1]));
for(int j = 0; j <= sumA; j++)
for(int a = 0; a < 2; a++)
for(int b = 0; b < 2; b++) if(~dp[o][j][a][b]){
for(int k = 0; k <= yu[i+1]; k++){
int ta = k, tb = yu[i+1] - k, tmp = ta / (2 * s[i+1].a) + tb / (2 * s[i+1].a);
int na = a, nb = b;
ta %= (2 * s[i+1].a), tb %= (2 * s[i+1].a);
if(ta == 2 * s[i+1].a - 1) tmp += (++na == 1);
if(tb == 2 * s[i+1].a - 1) tmp += (++nb == 2);
up(dp[o^1][j+k][na&1][nb&1], dp[o][j][a][b] + tmp * s[i+1].c);
}
}
}
int mx = 0;
for(int i = 0; i <= min(sum / 2, sumA); i++) if(f[sum/2-i]){
for(int a = 0; a < 2; a++)
for(int b = 0; b < 2; b++) mx = max(mx, dp[n&1][i][a][b]);
}
cout << mx + ans;
return 0;
}

「CSA49」Card Collecting Game的更多相关文章

  1. 「CSA49」Bunny on Number Line

    「CSA49」Bunny on Number Line 题目大意:有一个人从0开始走,每次可以向前走一步或者回到1,那么会产生一个位置序列,其中给出 \(k\) 个位置是好的.定义一个位置序列是好的, ...

  2. 「MoreThanJava」计算机发展史—从织布机到IBM

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

  3. 直播预告|App 首页如何动态化更新?来看蚂蚁技术专家详解「支付宝」全新卡片技术栈

    立即前往直播间预约观看 从icon到card,一场内容前置化的变革 从 Windows 时代开始,应用程序图标就成为了用户(流量)的主入口,一直持续到移动端时代. 图标即入口的方式,虽然足够方便但却不 ...

  4. 「译」JUnit 5 系列:条件测试

    原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...

  5. 「译」JUnit 5 系列:扩展模型(Extension Model)

    原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...

  6. JavaScript OOP 之「创建对象」

    工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程.工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题. function createPers ...

  7. 「C++」理解智能指针

    维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...

  8. 「JavaScript」四种跨域方式详解

    超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由. 1. JSONP 首先要介绍的跨域方法必然是 JSON ...

  9. 「2014-5-31」Z-Stack - Modification of Zigbee Device Object for better network access management

    写一份赏心悦目的工程文档,是很困难的事情.若想写得完善,不仅得用对工具(use the right tools),注重文笔,还得投入大把时间,真心是一件难度颇高的事情.但,若是真写好了,也是善莫大焉: ...

随机推荐

  1. 在C++11中实现监听者模式

    参考文章:https://coderwall.com/p/u4w9ra/implementing-signals-in-c-11 最近在完成C++大作业时,碰到了监听者模式的需求. 尽管C++下也可以 ...

  2. frameset测试

    frame不能放在body标签内.指定name属性,为这一个框架指定名字,在html的a的target属性可以设为target="right"在该框架显示跳转的页面.(常用于后台管 ...

  3. windows下phpstrom中xdebug的使用

    https://laravel-china.org/articles/16425/windows-phpstorm-xdebug-breakpoint-debugging

  4. VMW虚拟机生成的文件说明

    VMDK(VMWare Virtual Machine Disk Format)是虚拟机VMware创建的虚拟硬格式,文件存在于VMware文件系统中,被称为VMFS(虚拟机文件系统) NVRAM 非 ...

  5. mysql军规

    总是在灾难发生后,才想起容灾的重要性.总是在吃过亏后,才记得曾经有人提醒过. 一,核心军规 不在数据库做计算,cpu计算务必移至业务层 控制单表数据量,单表记录控制在千万级 控制列数量,字段数控制在2 ...

  6. PYTHON学习(三)之利用python进行数据分析(1)---准备工作

    学习一门语言就是不断实践,python是目前用于数据分析最流行的语言,我最近买了本书<利用python进行数据分析>(Wes McKinney著),还去图书馆借了本<Python数据 ...

  7. Remove Duplicates from Sorted List II——简单的指针问题

    Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numb ...

  8. 【hdoj_1753】大明A+B(大数)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1753 本题要求是,进行多位的小数加法,由于位数很多,所以不能用double类型存储,可以用字符串存储,然后 ...

  9. 使用BEEGO建立一个基本的API框架

    用BEE API命令生成框架. 然后自行更改MODELS,加入MYSQL支持ORM. 然后,自定义了字段的对应,表的名称等. 参考URL: http://www.cnblogs.com/studyzy ...

  10. 使用jdk自带的工具native2ascii 转换Unicode字符和汉字

    1.控制台转换 1.1 将汉字转为Unicode: C:\Program Files\Java\jdk1.5.0_04\bin>native2ascii 测试 \u6d4b\u8bd5 1.2 ...