「CSA49」Card Collecting Game
「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的更多相关文章
- 「CSA49」Bunny on Number Line
「CSA49」Bunny on Number Line 题目大意:有一个人从0开始走,每次可以向前走一步或者回到1,那么会产生一个位置序列,其中给出 \(k\) 个位置是好的.定义一个位置序列是好的, ...
- 「MoreThanJava」计算机发展史—从织布机到IBM
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
- 直播预告|App 首页如何动态化更新?来看蚂蚁技术专家详解「支付宝」全新卡片技术栈
立即前往直播间预约观看 从icon到card,一场内容前置化的变革 从 Windows 时代开始,应用程序图标就成为了用户(流量)的主入口,一直持续到移动端时代. 图标即入口的方式,虽然足够方便但却不 ...
- 「译」JUnit 5 系列:条件测试
原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...
- 「译」JUnit 5 系列:扩展模型(Extension Model)
原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...
- JavaScript OOP 之「创建对象」
工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程.工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题. function createPers ...
- 「C++」理解智能指针
维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...
- 「JavaScript」四种跨域方式详解
超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由. 1. JSONP 首先要介绍的跨域方法必然是 JSON ...
- 「2014-5-31」Z-Stack - Modification of Zigbee Device Object for better network access management
写一份赏心悦目的工程文档,是很困难的事情.若想写得完善,不仅得用对工具(use the right tools),注重文笔,还得投入大把时间,真心是一件难度颇高的事情.但,若是真写好了,也是善莫大焉: ...
随机推荐
- JSDom
什么是Dom? 1.简介 文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标志语言的标准编程接口.Document Object Model的历史可 ...
- Linux下命令lrzsz
lrzsz是什么 在使用Linux的过程中,难免少不了需要上传下载文件,比如往服务器上传一些war包之类的,之前都是使用winSCP,lrzsz是一个更方便的命令,可以直接在Linux中输入命令,弹出 ...
- vc 播放音乐
#include <vfw.h> #pragma comment(lib,"vfw32.lib") ● 简单实现 要实现一个播放器,首先要先建立一个MF ...
- 【Git】git clone与git pull区别
从字面意思也可以理解,都是往下拉代码,git clone是克隆,git pull 是拉.但是,也有区别: 从远程服务器克隆一个一模一样的版本库到本地,复制的是整个版本库,叫做clone.(clone是 ...
- 17 - 路径操作-shutil模块
目录 1 路径操作 1.1 os.path模块 1.2 pathlib模块 1.2.1 目录操作 1.2.2 文件操作 1.3 os 模块 2 shutil模块 2.1 copy复制 2.2 rm删除 ...
- python并发编程之Queue线程、进程、协程通信(五)
单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...
- 宋牧春: Linux设备树文件结构与解析深度分析(1) 【转】
转自:https://mp.weixin.qq.com/s/OX-aXd5MYlE_YoZ3p32qWA 作者简介 宋牧春,linux内核爱好者,喜欢阅读各种开源代码(uboot.linux.ucos ...
- USB 3.0传输规格
通用序列总线(USB) 从1996问世以来,一统个人电脑外部连接界面,且延伸至各式消费性产品,早已成为现代人生活的一部分.2000年发表的USB 2.0 High-speed规格,提供了480Mbps ...
- 千字短文解决工程师们关于SPI的迷糊!
串行外设接口 (SPI) 总线是一个工作在全双工模式下的同步串行数据链路.它可用于在单个主控制器和一个或多个从设备之间交换数据.其简单的实施方案只使用四条支持数据与控制的信号线(图 1): 图1:基本 ...
- selenium滚动到顶部与底部
#coding=utf-8 from selenium import webdriver #滚动到浏览器顶部 js_top = "var q=document.documentElement ...