QZOI2019 CSP-S模拟赛 T1

错误的贪心导致考场上只有10pts... 看来以后贪心还是需要先证明啊

题目描述

小A和小B在玩一个游戏,他们两个人每人有 $n$ 张牌,每张牌有一个点数,并且在接下来的 $n$ 个回合中每回合他们两人会分别打出手中的一张牌,点数严格更高的一方得一分,然而现在小A通过某种神秘的方法得到了小B的出牌顺序,现在他希望规划自己的出牌顺序使得自己在得分尽可能高的前提下出牌的字典序尽可能大。

题意分析

给出一个数列$b$,给出一个相同长度的数列$a$,要求重新排列$a$,使得最多的$a_i>b_i$,输出字典序最大的一种方案。

思路分析

很自然地想到贪心。

考场上:字典序最大,那倒着最小不就得了(草我是什么sb),10pts

为什么是错的?实际上,如果在线输入在线构造数列$a$,有很多种情况会导致错误。

可以发现,得分与数列的顺序是没有关系的。因此我们完全可以先构造出最大得分,再来构造最大字典序。

具体实现

怎么构造最大得分?可以将$a$和$b$都排序,然后降序遍历$b$,对于当前的$b$,如果当前的$a_i$能得分,就得一分;否则继续遍历。

然后我们构造出一个得分方案。设想,构造出一个得分方案后,我们为了保证得分不变,不能再动已经定下来的这些牌;但我们可以用更大的牌来代替其中的一些牌,这样得分不变。因此我们先构造出一个最小的方案,这样剩下的大牌可以放到不得分的地方,也可以来替代得分的地方,可能性才多。当然,对于构造出的这个方案,我们也要使它在不改变牌组成的情况下,字典序最大。我们暂且将这些没有得分的大牌称为活动牌。

然后我们就开始从前往后遍历$b$序列,若当前元素处于得分方案内,看看有没有活动牌可以替代它,如果有,就用这张牌替代它,并让原来的方案牌成为活动牌;若当前元素不处于得分方案内,我们也可以从方案牌中拿一张最大的牌,当然,如果要拿牌,这张牌一定要可以得分,否则会导致得分减少,同时,因为这里会从方案牌中拿牌,处理得分方案内的牌时,要注意判断当前分配到的方案牌有没有提前被取走。

以上的算法可以通过multiset实现,部分步骤也可以用大根堆替代以降低复杂度,但比较复杂。

下面给出本文代码中用到的一些multiset操作的解释:(可以参考蓝书或网上资料)

multiset<int> s:定义一个有序可重集s
multiset<int>::iterator it:定义一个迭代器it,可以用“*”取消引用
s.insert(x):向s中插入数x
s.erase(it):从s中删除迭代器it指向的元素
s.find(x):返回s中指向x的迭代器
s.begin():返回s中指向第一个元素的迭代器
s.end():返回s中指向最后一个元素后一个地址的迭代器
s.rbegin():返回s中指向最后一个元素的反向迭代器,反向的意思是,若执行++操作,则会向s的前一位移动

考场上忘记函数怎么写怎么办?打开Dev-Cpp目录,搜索头文件set,找到对应的函数即可

//贪心
//先保证得分最大,再保证字典序最大。可以先处理出最大得分的一种方案,然后再调整字典序到最大
//其它有的贪心算法可能会导致字典序或者得分顾此失彼,是错误的
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#define id(i) w[i].id
#define v(i) w[i].v
using namespace std;
const int N=1e5+100;
struct B
{
int id,v;
}w[N];
int n,cnt;
int b[N],ans[N];
multiset<int> s1,s2;
multiset<int>:: iterator it;
bool cmp(B x,B y)
{
return x.v<y.v;
}
int main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]),v(i)=b[i],id(i)=i;
for(int i=1,x;i<=n;i++)
scanf("%d",&x),s1.insert(x),s2.insert(x);
sort(w+1,w+n+1,cmp);
for(int i=n;i;i--)
if(*s2.rbegin()>v(i))
cnt++,s2.erase(s2.find(*s2.rbegin()));//计算最大得分
//先构造出一种出牌最小的方案,这样剩下的活动的牌就大,构造大字典序的空间就大
//本步过后,s1存储的就是方案外的活动牌
//活动牌的定义是,不可以得分的,可以随意移动的牌
for(int i=1;i<=cnt;i++)
{
it=s1.upper_bound(v(i));
ans[id(i)]=*it;s1.erase(s1.find(*it));
}
s2.clear();
for(int i=1;i<=n;i++)
if(ans[i])
s2.insert(ans[i]);//s2存储已构造出的一种方案
for(int i=n;i;i--)
if(ans[i])
{
it=s2.upper_bound(b[i]);
ans[i]=*it,s2.erase(it);
}//将s2的字典序弄到最大
for(int i=1;i<=n;i++)
if(ans[i])
s2.insert(ans[i]);//再存回去
//不改变原方案的牌,为了使字典序最大,可以在活动牌和本来分配给它的牌中找最大的
for(int i=1;i<=n;i++)
if(ans[i] && s2.find(ans[i])!=s2.end())//原方案已分配的部分
s1.insert(ans[i]),s2.erase(s2.find(ans[i])),printf("%d ",*s1.rbegin()),s1.erase(s1.find(*s1.rbegin()));
else//没被分配到的部分
{
if(s2.size() &&(*s1.rbegin()>b[i] || *s2.rbegin()>b[i]))//可以在s2中取个最大的拉过去得分
s1.insert(*s2.rbegin()),s2.erase(s2.find(*s2.rbegin()));
printf("%d ",*s1.rbegin()),s1.erase(s1.find(*s1.rbegin()));
}
return 0;
}

[QZOI2019]Game 题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

随机推荐

  1. PHP simplexml_import_dom() 函数

    实例 获取 DOM 文档节点并转换为 SimpleXML 节点: <?php$dom=new domDocument;高佣联盟 www.cgewang.com$dom->loadXML(& ...

  2. C/C++编程笔记:C语言写推箱子小游戏,大一学习C语言练手项目

    C语言,作为大多数人的第一门编程语言,重要性不言而喻,很多编程习惯,逻辑方式在此时就已经形成了.这个是我在大一学习 C语言 后写的推箱子小游戏,自己的逻辑能力得到了提升,在这里同大家分享这个推箱子小游 ...

  3. [转]Java死锁排查

    文章来源:微信公众号:猿天地 1. 死锁的概念: 是Java多线程情况下,两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞现象,若无外力作用,它们都讲无法推进下去.此时称 ...

  4. 【SCOI2005】互不侵犯 题解(状压DP)

    前言:一道状压DP的入门题(可惜我是个DP蒟蒻QAQ) ------------------ 题意简述:求在一个$n*n$的棋盘中放$k$个国王的方案数.注:当在一个格子中放入国王后,以此格为中心的九 ...

  5. Android线性布局和帧布局

    第二次,本牛崽十分从容,今天咱们来讲讲Android Q之布局,我遇到的问题与自己学到的,大牛不要嘲笑哈,有错误可以指出来,本牛崽看到就改了. 今天我的学长跟我们开始了布局,布局看资料说好像有5种,又 ...

  6. python7.1处理异常

    a=[21,32,43,0,32,"a"]for i in a:#取出元素 try:#写可能会报错的代码 print(3/i) except Exception as e:#捕获t ...

  7. 【av68676164(p41-p42)】内存管理功能

    存储器的功能需求 容量足够大 速度足够快 信息永久保存 多道程序并行 多道程序并行带来的问题 共享:代码和数据共享,节省内存 保护:不允许内存中的程序相互间非法访问 实际存储器体系 三级存储体系 Ca ...

  8. 微信公众号怎么添加附件?比如word文档,pdf文件等

    微信公众号怎么添加附件?比如word文档,pdf文件等   我们都知道创建一个微信公众号,在公众号中发布一些文章是非常简单的,但公众号添加附件下载的功能却被限制,如今可以使用小程序“微附件”进行在公众 ...

  9. 社区观点 | 理解比原链MOV链上交换协议

    去中心化交换协议的发展 从Bitshare,Stellar到以太坊上的Etherdelta,Bancor,0x协议,去中心化交换协议也经过了好几代发展和很多模式的探索,每一代都通过前面的协议的痛点来进 ...

  10. C# ASP response.write()弹出提示框后页面布局被打乱

    发现在使用了response.write后样式发生了变化,位置和字体都不正确.Response.Write("<script>alert(')</script>&qu ...