题目

描述

题目大意

有111到2n2n2n牌,一开始分别给两个人,每人nnn张。

轮流出牌,给出对手出牌的顺序,若自己的牌更大,就记一分。

在中间的某个时刻可以改变游戏规则。

问最大的分数。


思考历程

显然,一定是把大的放分界点左边,把小的放右边。

那可以枚举分界点,两边分别计算就可以了。时间复杂度为O(n2)O(n^2)O(n2),朴素的暴力算法。

接下来我就想有没有什么数据结构可以在枚举分界点的时候维护左右两边的答案。

想不出……

换种简单的思路。

当分界点从左向右移动的时候,左边的答案会增,右边的答案回减。

于是我就天真地想到了三分(如果画成函数图像就是一座山峰),打了个三分上去。

最终沮丧地发现三分是错的,不过还好,可以水到50分。

但实际上这并不是一座山峰,而是连绵起伏,没有什么规律……

莫名其妙地想到模拟退火,可不可以用它来AC这题?


正解

其实这题的解法比较多样,先说题解做法(我AC的做法):

枚举分界点,用数据结构维护左右两边的答案。

如何维护呢?

现在我们只考虑左边,右边的可以分开处理,方法是一模一样的。

我们现在有个大小为2n2n2n的桶,枚举到某个分界点时,这个桶里面有一些点有值,表示这个点存在。这个值还表示它是敌方还是我方。

接下来敌方点要分别在右边匹配我方点,使得匹配数最大。

然后就有一个比较粗暴的思路:可以考虑匹配最近的点。

用个线段树来维护,对于每个节点,记录当前区间内的我方点和敌方点的个数。

合并区间的时候,用左区间的敌方点配对右区间的我方点(尽量配对),加入答案,然后将剩余的加在一起。

这样就使得近的点先匹配到一起。

这个思路是正确的。不妨想想,对于每个敌方点,它们只能匹配在右边的我方点。显然从右到左,它们可以选择的集合的大小是递增的。既然要让匹配数最大,就应当尽量让左边的点在它的集合以内,并且右边的点的集合以外的,这样就不会影响右边的点的选择。所以匹配的最好方式是选择最近的点。

但合并的过程是从小区间到大区间,顺序是乱的,有没有可能出问题呢?出问题的原因在于两个点右边最近的点重合了。如果这样,就其中一个选点,然后另一个会再往后面找。我们不需要关心到底是哪个先选点,因为这样是等价的,我们没有必要关心这些。

有了这个数据结构之后扫一遍,记录答案就可以做出来了,时间复杂度O(nlg⁡n)O(n\lg n)O(nlgn)

还有一个DYP发明的不同算法。主要思路是在桶中枚举,然后用数据结构来修改答案(把答案看成一个序列)。

先把左右两边分开计算(一下以左边为准)。开一个2n2n2n大小的桶。

根据贪心策略,从右到左,然后能匹配就匹配的方案一定是最优的。

从大到小在桶中扫,用一个变量来记录扫到的我方的数量。

遇见一个敌方的点,就开始搞事情:它可能会匹配右边的点。如果右边有点,那就可以匹配,它出现的时间那里的答案加一。如果右边的点,那就不可以匹配,就不加一。

我们维护的是整个答案序列。显然答案序列是递增的。所以可以在数据结构中二分出一个尽量后的地方,使得它的答案小于我方的数量,这就意味着在它后面时间中,那右边的点被占满了。所以就将它出现的时间和二分出来的时间形成的这段区间加一。

做完这些后就记录左边和右边的答案,然后合并。在之前我们可以记录当前的这个答案用到的最右(最左)的我方点位置,表示选取我方点的区间。合并的时候,如果区间重合,那鱼与熊掌不可得兼,减去重合部分就是真正的答案了。


代码

题解方法

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 50010
int n;
int a[N],b[N*2];
bool flag[N*2];
struct Node{
int p,d,w;
} d[N*8];
inline void update1(int k){
int newp=min(d[k<<1].w,d[k<<1|1].d);//两边的最大匹配数
d[k]={d[k<<1].p+d[k<<1|1].p+newp,d[k<<1].d+d[k<<1|1].d-newp,d[k<<1].w+d[k<<1|1].w-newp};
}
inline void add1(int k,int l,int r,int x){
if (l==r){
if (flag[x])
d[k]={0,0,1};
else
d[k]={0,1,0};
return;
}
int mid=l+r>>1;
if (x<=mid)
add1(k<<1,l,mid,x);
else
add1(k<<1|1,mid+1,r,x);
update1(k);
}
inline void update2(int k){
int newp=min(d[k<<1].d,d[k<<1|1].w);
d[k]={d[k<<1].p+d[k<<1|1].p+newp,d[k<<1].d+d[k<<1|1].d-newp,d[k<<1].w+d[k<<1|1].w-newp};
}
inline void add2(int k,int l,int r,int x){
if (l==r){
if (flag[x])
d[k]={0,0,1};
else
d[k]={0,1,0};
return;
}
int mid=l+r>>1;
if (x<=mid)
add2(k<<1,l,mid,x);
else
add2(k<<1|1,mid+1,r,x);
update2(k);
}
int ans1[N],ans2[N];
int main(){
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]),flag[a[i]]=1;
for (int i=1,j=0;i<=n*2;++i)
if (!flag[i])
b[++j]=i;
for (int i=0;i<n;++i){
ans1[i]=d[1].p;
add1(1,1,n<<1,a[i+1]);
add1(1,1,n<<1,b[n-i]);
}
ans1[n]=d[1].p;
memset(d,0,sizeof d);
for (int i=n;i>0;--i){
ans2[i]=d[1].p;
add2(1,1,n<<1,a[i]);
add2(1,1,n<<1,b[n-i+1]);
}
ans2[0]=d[1].p;
int ANS=0;
for (int i=0;i<=n;++i)
ANS=max(ANS,ans1[i]+ans2[i]);
printf("%d\n",ANS);
return 0;
}

总结

其实这是一个分治思路,只是用数据结构来动态实现罢了。

所以还是可以往分治方面想……

[JZOJ4684] 【GDOI2017模拟8.11】卡牌游戏的更多相关文章

  1. BZOJ_3191_[JLOI2013]卡牌游戏_概率DP

    BZOJ_3191_[JLOI2013]卡牌游戏_概率DP Description   N个人坐成一圈玩游戏.一开始我们把所有玩家按顺时针从1到N编号.首先第一回合是玩家1作为庄家.每个回合庄家都会随 ...

  2. 洛谷 P2059 [JLOI2013]卡牌游戏 解题报告

    P2059 [JLOI2013]卡牌游戏 题意 有\(n\)个人玩约瑟夫游戏,有\(m\)张卡,每张卡上有一个正整数,每次庄家有放回的抽一张卡,干掉从庄家起顺时针的第\(k\)个人(计算庄家),干掉的 ...

  3. bzoj千题计划202:bzoj3191: [JLOI2013]卡牌游戏

    http://www.lydsy.com/JudgeOnline/problem.php?id=3191 每个人获胜的概率只与其在排列中与庄家的相对位置有关 dp[i][j] 还剩i个人时,从庄家数第 ...

  4. 【BZOJ3191】【JLOI2013】卡牌游戏 [DP]

    卡牌游戏 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description   N个人坐成一圈玩游戏.一开始我 ...

  5. TCG卡牌游戏研究:《炉石战记:魔兽英雄传》所做的改变

    转自:http://www.gameres.com/665306.html TCG演进史 说到卡牌游戏,大家会联想到什么呢? 是历史悠久的扑克牌.风靡全球的<MTG 魔法风云会>与< ...

  6. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  7. BZOJ 4392 卡牌游戏

    Description 奶牛贝茜是卡牌游戏的狂热爱好者, 但是令人吃惊的, 她缺乏对手. 不幸的是, 任何牧 群里的其他牛都不是好对手. 他们实在是太差了 , 实际上, 他们玩卡牌游戏时会遵循一种完全 ...

  8. [JLOI2013]卡牌游戏 概率DP

    [JLOI2013]卡牌游戏 概率DP 题面 \(dfs\)复杂度爆炸,考虑DP.发现决策时,我们只用关心当前玩家是从庄家数第几个玩家与当前抽到的牌是啥.于是设计状态\(f[i][j]\)表示有\(i ...

  9. [省选联考 2021 A/B 卷] 卡牌游戏

    垃圾福建垫底选手来看看这题. 大家怎么都写带 \(log\) 的. 我来说一个线性做法好了. 那么我们考虑枚举 \(k\) 作为翻转完的最小值. 那么构造出一个满足条件的操作,我们在 \(a_i\) ...

  10. JLOI 2013 卡牌游戏

    问题描述: N个人坐成一圈玩游戏.一开始我们把所有玩家按顺时针从1到N编号.首先第一回合是玩家1作为庄家.每个回合庄家都会随机(即按相等的概率)从卡牌堆里选择一张卡片,假设卡片上的数字为X,则庄家首先 ...

随机推荐

  1. Spring 源码学习——加载 Bean

    继上次注册 bean 之后好久没更新,这两天有空查了查资料也自己看了看 spring BeanFactory 的 getBean(beanName); 这个方法.因时间有限不能像之前那样复制代码并一行 ...

  2. C++之程序流程_选择结构

    C/C++支持最基本的三种程序运行结构:==顺序结构.选择结构.循环结构== * 顺序结构:程序按顺序执行,不发生跳转* 选择结构:依据条件是否满足,有选择的执行相应功能* 循环结构:依据条件是否满足 ...

  3. springboot整合thymeleaf手动渲染

    Thymeleaf手动渲染 为提高页面访问速度,可缓存html页面,客户端请求从缓存获取,获取不到再手动渲染 在spring4下 @Autowired ThymeleafViewResolver th ...

  4. sys_call_table HOOK

    sys_call_table 这个东西,其实和 Windows 下的 SSDT 表,在功能上完全相同. 前一阵子学Linux驱动,遇到了这个系统调用表,然后我就想到Windows的SSDT表,既然SS ...

  5. lvs负载均衡连接

    http://blog.csdn.net/zwz1984/article/details/45194377 http://blog.csdn.net/zwz1984/article/details/4 ...

  6. Vultr IP被墙该怎么办

    我们创建好Vultr服务器时候,首先需要检测IP地址是否可用,很多IP在国内被墙,导致使用Xshell连接不上,虽然IP能够ping通,但是SSH依然连接不上.那Vultr IP被墙该怎么办呢? 方法 ...

  7. MySQL安装pdf介绍

    pdf地址:https://files.cnblogs.com/files/pygo/mysql%E5%AE%89%E8%A3%85.pdf

  8. SpringCloud及其五大常用组件之Eureka和Zuul

    1.springcloud简介 SpringCloud是Spring旗下的项目之一,它是微服务架构的一种实现方式. 官网地址:http://projects.spring.io/spring-clou ...

  9. AutoMapper Profile用法

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using AutoMappe ...

  10. POJ-2499-Binary Tree-思维题

    Background Binary trees are a common data structure in computer science. In this problem we will loo ...