题目大意

  不会博弈论的 yww 在和博弈论大师 yxq 玩一个游戏。

  有 \(n\) 种卡牌,第 \(i\) 种卡牌有 \(b_i\) 张。

  yww 会先把所有 \(B=\sum_{i=1}^nb_i\) 张卡分成两堆,每堆 \(\frac{B}{2}\) 张。保证 \(B\) 是偶数。

  他们会轮流从第一堆中取卡牌,每次取一张,yww 先取,直到取完为止。

  然后他们会轮流从第二堆中取卡牌,每次取一张,yxq 先取,直到取完为止。

  取完卡牌后,他们会计算自己的得分。假设某人在某一堆中取了 \(x\) 张第 \(i\) 种卡牌,那么就能获得 \(\lfloor\frac{x}{a_i}\rfloor c_i\) 分。

  每个人的最终得分是这个人在两堆中的得分之和。

  yxq 想最小化 yww 的得分。

  作为一名博弈论大师,yxq 每步都会执行最优策略。

  yww 不会博弈论,所以请你帮 yww 求出他最多能获得多少分。

  记 \(A=\sum_{i=1}^na_i,B=\sum_{i=1}^nb_i\);

  \(1\leq a_i\leq A\leq 2000,1\leq b_i\leq B\leq 500000,2\mid B,1\leq n\leq 2000,1\leq c_i\leq 3000\);

题解

  考虑对于一堆牌,yww 先手,他能获得多少分。

  对于一种牌 \(i\),如果 \(b_i\equiv -1 \pmod {2a_i}\),那么先开始拿这种牌的人可以拿到 \(\lfloor \frac{b_i}{2a_i}\rfloor+1\) 张,其他情况都只能拿到 \(\lfloor\frac{b_i}{2a_i}\rfloor\) 张。

  记 \(b_i\equiv -1 \pmod {2a_i}\) 的牌为特殊的牌,按照 \(c_i\) 从大到小排序,记为 \(d_1,d_2,\ldots,d_k\),那么最终先手的得分是 \(\sum\limits_i \lfloor\frac{b_i}{2a_i}\rfloor c_i+\sum\limits_{2\nmid i} c_{d_i}\),后手的得分是 \(\sum\limits_i \lfloor \frac{b_i}{2a_i}\rfloor c_i+\sum\limits_{2\mid i} c_{d_i}\)。

  这样就可以设计DP状态了:

  \(f_{i,j,p1,p2}\) 为前 \(i\) 种牌,第一堆分了 \(j\) 张,第一堆有 \(p1\) 种特殊的牌,第二堆有 \(p2\) 种特殊的牌,yww 的最大收益。

  转移时枚举第 \(i\) 种牌分多少到第一堆。

  复杂度为 \(O(B^2)\)。

  注意到收益只与每种牌分到第一堆的牌数 \(\bmod {2a_i}\) 有关,那么DP的时候就可以只枚举 模 \(2a_i\) 的值就好了。

  还有一个问题,第一堆牌能不能凑出 \(\frac{B}{2}\) 张?

  对于一种牌,假设我们把 \(k\) 张牌放到了第一堆,那么有 \(\lfloor\frac{b_i-k}{2a_i}\rfloor\) 组 \(2a_i\) 张牌可以随意分配。这个东西等于 \(\lfloor\frac{b_i}{2a_i}\rfloor\) 或 \(\lfloor\frac{b_i}{2a_i}\rfloor -1\)。我们假装它等于 \(\lfloor\frac{b_i}{2a_i}\rfloor -1\)。

  只可能有 \(O(\sqrt{A})\) 种不同的 \(a_i\),随便DP一下就好了。

  记 \(g_{i,j}\) 为用了前 \(i\) 种 \(a_i\) 组出 \(j\) 张卡牌,第 \(i\) 种 \(a_i\) 最少要多少份(每份 \(2a_i\) 张)(\(-1\) 表示组不出)。

  时间复杂度为 \(O(A^2+B\sqrt A)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<functional>
#include<cmath>
#include<vector>
#include<assert.h>
//using namespace std;
using std::min;
using std::max;
using std::swap;
using std::sort;
using std::reverse;
using std::random_shuffle;
using std::lower_bound;
using std::upper_bound;
using std::unique;
using std::vector;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
void open(const char *s){
#ifndef ONLINE_JUDGE
char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
void open2(const char *s){
#ifdef DEBUG
char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
const int N=2010;
const int M=500010;
int f[N][2][2][4*N];
int s[N];
int qs[N];
int c[M];
int g[M];
struct info
{
int a,q,v;
};
info a[N];
int cmp(info a,info b)
{
return a.v>b.v;
}
int n;
int main()
{
open("49F");
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&a[i].a,&a[i].q,&a[i].v);
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
s[i]=s[i-1]+4*a[i].a;
qs[i]=qs[i-1]+a[i].q;
}
memset(f,0x80,sizeof f);
f[0][0][0][0]=0;
for(int i=1;i<=n;i++)
for(int l1=0;l1<=1;l1++)
for(int l2=0;l2<=1;l2++)
{
int x=a[i].q/(2*a[i].a)-1;
for(int k=0;k<=a[i].q;k++)
{
int v1=k/(2*a[i].a);
int v2=(a[i].q-k)/(2*a[i].a);
if(v2<x)
break;
int temp=(v1+v2)*a[i].v;
int p1=l1,p2=l2;
if(v1*2*a[i].a+2*a[i].a-1==k)
{
p1?0:temp+=a[i].v;
p1^=1;
}
if(v2*2*a[i].a+2*a[i].a-1==a[i].q-k)
{
p2?temp+=a[i].v:0;
p2^=1;
}
for(int j=0;j<=s[i-1];j++)
f[i][p1][p2][j+k]=max(f[i][p1][p2][j+k],f[i-1][l1][l2][j]+temp);
}
}
for(int i=1;i<=n;i++)
if(a[i].q/(2*a[i].a)-1>0)
c[a[i].a]+=a[i].q/(2*a[i].a)-1;
memset(g,-1,sizeof g);
g[0]=0;
for(int i=1;i<=s[n];i++)
if(c[i])
{
for(int j=0;j<=qs[n];j++)
if(~g[j])
g[j]=0;
else if(j>=2*i&&(g[j-2*i]>=0&&g[j-2*i]<c[i]))
g[j]=g[j-2*i]+1;
else
g[j]=-1;
}
int ans=0;
for(int i=0;i<=s[n]&&i<=qs[n]/2;i++)
if(~g[qs[n]/2-i])
for(int i1=0;i1<=1;i1++)
for(int i2=0;i2<=1;i2++)
ans=max(ans,f[n][i1][i2][i]);
printf("%d\n",ans);
return 0;
}

【CSA49F】【XSY3317】card 博弈论 DP的更多相关文章

  1. 2018.09.25 poj2068 Nim(博弈论+dp)

    传送门 题意简述:m个石子,有两个队每队n个人循环取,每个人每次取石子有数量限制,取最后一块的输,问先手能否获胜. 博弈论+dp. 我们令f[i][j]f[i][j]f[i][j]表示当前第i个人取石 ...

  2. 【uoj#51】[UR #4]元旦三侠的游戏 博弈论+dp

    题目描述 给出 $n$ 和 $m$ ,$m$ 次询问.每次询问给出 $a$ 和 $b$ ,两人轮流选择:将 $a$ 加一或者将 $b$ 加一,但必须保证 $a^b\le n$ ,无法操作者输,问先手是 ...

  3. 【bzoj4550】小奇的博弈 博弈论+dp

    题目描述 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色.最左边是白色棋子,最右边 是黑色棋子,相邻的棋子颜色不同.   小奇可以移动白色棋子,提比可以移动黑色的棋子, ...

  4. 「模拟赛20181025」御风剑术 博弈论+DP简单优化

    题目描述 Yasuo 和Riven对一排\(n\)个假人开始练习.斩杀第\(i\)个假人会得到\(c_i\)个精粹.双方轮流出招,他们在练习中互相学习,所以他们的剑术越来越强.基于对方上一次斩杀的假人 ...

  5. BZOJ_2017_[Usaco2009 Nov]硬币游戏_博弈论+DP

    BZOJ_2017_[Usaco2009 Nov]硬币游戏_博弈论+DP Description 农夫约翰的奶牛喜欢玩硬币游戏,因此他发明了一种称为“Xoinc”的两人硬币游戏. 初始时,一个有N(5 ...

  6. 湖南大学第十四届ACM程序设计新生杯(重现赛)I:II play with GG(博弈论||DP)

    链接:https://ac.nowcoder.com/acm/contest/338/I 来源:牛客网 题目描述 IG won the S championship and many people a ...

  7. POJ2068 Nim 博弈论 dp

    http://poj.org/problem?id=2068 博弈论的动态规划,依然是根据必胜点和必输点的定义,才明白过来博弈论的dp和sg函数差不多完全是两个概念(前者包含后者),sg函数只是mex ...

  8. bzoj 2798 [Poi2012]Bidding 博弈论+dp

    题目大意 A和B两个人在玩一个游戏,这个游戏是他们轮流操作一对整数(x,y). 初始时(x,y)=(1,0),可以进行三种操作: 将(x,y)变成(1,x+y). 将(x,y)变成(2x,y). 将( ...

  9. [CSP-S模拟测试]:取石子(博弈论+DP)

    题目描述 有三堆石子,它们的石子个数分别为$x,y,z$.$A$和$B$正在博弈,由$A$先手,双方轮流操作.每次操作是指,选择若干堆($1-3$堆)石子,从中各取出相同数量的石子(不能$1$个都不取 ...

随机推荐

  1. PyTorch入门(一)向量

    什么是PyTorch?   PyTorch是Facebook人工智能团队开发的一个机器学习和深度学习工具,用于处理大规模图像分析,包括物体检测,分割与分类.但是它的功能不仅限于此.它与其它深度学习框架 ...

  2. javascript 函数后面有多个小括号f( )( )( )...

    有时我们看见js函数后面跟着多个小括号是什么意思?f( )( )( )... f()执行f函数,返回子函数 f()()执行子函数,返回孙函数 f()()()执行孙函数,返回重孙函数 ... ... 但 ...

  3. cisco 下CEF(简介)[转载]

    cisco 下CEF(简介) 转自:http://blog.51cto.com/chengmingshu/803358 cms_cmd1人评论2570人阅读2012-03-12 00:09:29   ...

  4. 【设计模式】原型模式 Pototype Pattern

    前面讲了创建一个对象实例的方法单例模式Singleton Pattern, 创造多个产品的工厂模式(简单工厂模式 Simple Factory Pattern, 工厂方法模式 FactoryMothe ...

  5. 属于自己的MES(二)必备的主数据

    MES在系统建设前,需要先进行一些必要的数据,这些主数据是支撑MES执行的关键. 1.BOM BOM通常称为“物料清单”,也就是产品结构,在化工.制药.食品.烟草领域也叫“配方”,它主要描述了物料的物 ...

  6. .NET Core 学习笔记2——管理nuget包

    .NET Core 基于Nuget包.它是一个.nupkg后缀的zip文件. 工具 dotnet 工具 vs2017 的程序包管理控台 这两个工具都可以用命令行来下载安装,更新,上传包(上传要先在网站 ...

  7. 八皇后问题(C#)

    八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同 ...

  8. 使用cmd查看电脑连接过的wifi密码并将密码发送至指定邮箱(三)

    之前,我写了使用cmd查看电脑连接过的wifi密码(二)和使用cmd查看电脑连接过的wifi密码(一)但其中的功能不完善,在本次的更新中新增了更多的功能,其实2018/10/24 就更新完成了,一直拖 ...

  9. 记录Javascript集合操作

    function Set() { var items = {}; /** * 添加元素 * @param {[type]} value [description] */ this.add = func ...

  10. C#:System.Array简单使用

    1.C# 中的数组 1.1 定义数组: 1.1.1 定义不初始化:数据类型[] 数组名称= new 数据类型[元素个数];    1.1.2 定义并初始化:数据类型[] 数组名称= new 数据类型[ ...