[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 & ...
随机推荐
- ref以及传值传址的理解
ref(也包括out)关键字肯定都会用,传值调用和传址调用也是初学写代码时都已经历过的话题,与这相关的还有一些话题,比如值类型和引用类型有什么区别等,但是如果不仔细,可能有一些概念的混淆或者理解不够清 ...
- PHP readfile() 函数
定义和用法 readfile() 函数读取一个文件,并写入到输出缓冲. 如果成功,该函数返回从文件中读入的字节数.如果失败,该函数返回 FALSE 并附带错误信息.您可以通过在函数名前面添加一个 '@ ...
- PHP imagealphablending - 设定图像的混色模式
imagealphablending — 设定图像的混色模式.高佣联盟 www.cgewang.com 语法 bool imagealphablending ( resource $image , b ...
- python 调用百度接口 做人脸识别
操作步骤差不多,记得要在百度AIPI中的控制台中创建对应的工单 创建工单成功后 会生成两个key 这个两个key是要生成tokn 用 这里大家可以用 def函数 将token返回 供下面的接口使用 ...
- day14.推导式与生成器
一.列表推导式 '''通过一行循环判断,遍历一系列数据的方式''' """ 推导式的语法: val for val in Iterable 三种方式: [val for ...
- .Net Core HttpClient处理响应压缩
前言 在上篇文章[ASP.NET Core中的响应压缩]中我们谈到了在ASP.NET Core服务端处理关于响应压缩的请求,服务端的主要工作就是根据Content-Encoding头信息判断采 ...
- python6.4项目:股票提醒系统
import tushareimport timedef getdata(share): data=tushare.get_realtime_quotes(share.code) share.name ...
- 完了,这个硬件成精了,它竟然绕过了 CPU...
我们之前了解过了 Linux 的进程和线程.Linux 内存管理,那么下面我们就来认识一下 Linux 中的 I/O 管理. Linux 系统和其他 UNIX 系统一样,IO 管理比较直接和简洁.所有 ...
- 前端vue2-org-tree实现精美组织架构图
最近遇到开发组织架构的需求,与以往开发的组织架构不同,不光要展示人名,还要显示职务(或者子公司名称).对应的头像等,并且要考虑,如果用户未上传头像,需使用默认头像(男.女.中性),(⊙o⊙)…要尊重尊 ...
- Linux非交互方式设置密码
echo "123" | passwd -stdin lamp echo testuser:password|chpasswd 参考:Linux通过Shell脚本命令修改密码不需要 ...