[QZOI2019]Game 题解
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 题解的更多相关文章
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...
- 网络流n题 题解
学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...
- CF100965C题解..
求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...
随机推荐
- 图文并茂,带你认识 JVM 运行时数据区
跨平台的本质 关于 JVM, Java 程序员的最熟悉的一句话就是:一处编码,到处执行,指的就是 Java 语言可以通过 JVM 实现跨平台.而跨平台到底跨越了什么这个问题相信很少有人知道,接下来就跟 ...
- Filebeat日志收集简单使用
1.简略介绍 轻量型日志采集器,用于转发和汇总日志与文件. 官网: https://www.elastic.co/cn/beats/filebeat 2.本文实现的功能 3.事先必备: 至少一台Kaf ...
- 5.20 省选模拟赛 T1 图 启发式合并 线段树合并 染色计数问题
LINK:图 在说这道题之前吐槽一下今天的日子 520 = 1+1+4+514. /cy 这道题今天做的非常失败 一点分都没拿到手 关键是今天的T3 把我整个人给搞崩了. 先考虑 如果得到了这么一张图 ...
- html笔记 标签属性、图像和链接、超链接
HTML 标签属性: <b></b>:加粗 <i></i>:斜体 <u></u>:下划线 <s></s> ...
- GhostNet:more features from cheap operation
- Assembly.LoadFrom() 方法加载程序集,无法转换类型
有些情况在开发一个C#框架的时候,要用到反射加载另外程序集,这是必然考虑的事情.这样做的好处就是多个工程同时作业的时候,可以互不干扰,替换DLL文件即可. Assembly.Load();这个方法只能 ...
- three.js 制作机房(下)
这一篇书接上文,说一说剩下的一些模块. 1. 机箱存储占用比率 机箱存储占用比其实很简单,就是在机箱上新加一个组即可,然后根据比率值来设置颜色,这个颜色我们去HSL(0.4,0.8,0.5) ~ HS ...
- set学习记录
set是STL中的集合容器,其中每个元素都互不相同,并且都是以递增的形式排列. set只能使用迭代器访问. 说一下常用函数: 1.insert(x):插入函数用于把x插入set. 2.find(val ...
- 聊聊mysql中的int(1)
昨天有个读者问了我这样一个问题在mysql中建表的时候,我设置一个字段为int类型,长度为1,但是我发现这个字段却可以存储任意长度的数字,这是什么情况?这个问题在我刚接触数据库的时候也遇到过,我觉得有 ...
- 「MoreThanJava」Day 7:接口详解
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...