前天做了下美团的一个codeM比赛的资格赛,遇到一个题目挺有意思的,所以现在做一下总结。

题目描述

美团的每一个用户都有一个用户代金券的消费记录日志,每位用户都能购买若干种代金券,但是每一种代金券最多只能购买一张。如果现在手上已经有了一张某种的代金券,那么只有在消费完这张代金券之后才能再次购买同种代金券。每位用户的购买和消费记录都记录在日志文件中,字符I代表购买代金券,字符O代表消费代金券。现在由于系统出现故障,造成了日志文件的损坏,在这个文件中有些记录无法恢复,只能用字符?代替,现在需要你来检查这个日志文件中的记录是否是合理的,如果出现某些冲突则表示该日志文件出现错误。

例如在某位用户的消费记录日志中的记录是这样的:

I 1
O 1

代表用户首先购买了编号为1的代金券,然后又消费了该代金券,所以该日志文件是正确的。对于正确的日志文件我们输出-1。

如果消费记录是这样的:

I 1
I 1
O 1

因为用户重复购买了编号为1的代金券,这是不合理的,所以这个日志文件有问题,问题出现在第二行,所以我们应该输出2。

如果消费记录是这样的:

?
I 1
O 2

因为这个?是无法恢复的,所以可以看做是任何可能的记录,在这个例子中我们可以将它视为I 2,在这样的解释之下,这个日志文件是合理的,所以我们最终的输出是-1。

输入样例

首先我们需要输入一个m,表明这个日志文件的总的行数。之后就像上述的例子那样的输入。

2
I 1
O 1
3
I 1
I 1
O 1
3
?
I 1
O 2
4
I 1
?
O 1
O 1

输出样例

如果日志文件没有问题那么输出-1,如果有问题则输出最早出现问题的行数。

-1
2
-1
4

解题思路

当时没有想明白具体的逻辑,改了很久都没有过,今天问小崔才明白正确的解题思路。经过分析之后我们知道,输入?的时候是肯定不会有错误的,错误只能出现在IO的某行。那么当输入为I number的时候我们需要检查我们是否已经拥有这张代金券,如果没有那么这条记录是没有问题的,如果已经购买了这张代金券我们就应该进一步的检查,看上一次编号为number的代金券是什么时候买的,如果在这之间有一个?那么我们可以将这个?作为一个O number的记录,这样也就不会产生错误了。同样当输入为O number的时候我们同样按照相同的思路进行处理,如果有问题我们就应该进一步检查上一个相同编号的消费记录在什么时候,在这段时间内是否有?,如果有?我们就可以进行合理解释,否则就是一个错误的消费记录。

解题代码

#include <cstdio>
#include <set>
#include <cstring>
using namespace std;
const int maxn = 100000+10; int m, number;
char type;
int buy_time[maxn], sale_time[maxn];
bool coupon[maxn];
set<int> unsure;
set<int>::iterator idx;
int main() {
while (~scanf("%d", &m)) {
memset(buy_time, -1, sizeof(buy_time));
memset(sale_time, -1, sizeof(sale_time));
memset(coupon, false, sizeof(coupon));
unsure.clear();
int ans = -1;
for (int i = 1; i <= m; ++i) {
getchar();
scanf("%c", &type);
if (type == '?') {
unsure.insert(i);
} else {
scanf("%d", &number);
if (type == 'I') {
if (!coupon[number]) {
coupon[number] = true;
} else {
// 对处于上一个I与现在这个I之间的第一个?做一个处理,将它作为一个O使用
int preBuyTime = buy_time[number];
idx = unsure.lower_bound(preBuyTime); // 返回preBuyTime之后的第一个?的位置
if (idx != unsure.end()) {
unsure.erase(idx);
} else {
// 如果没有?可以用,那么就是错误情况了
if (ans == -1) {
ans = i;
}
}
}
buy_time[number] = i;
} else {
if (coupon[number]) {
coupon[number] = false;
} else {
// 对处于上一个O与现在这个O之间的第一个?做一个处理,将它作为一个I使用
int preSaleTime = sale_time[number];
idx = unsure.lower_bound(preSaleTime); // 返回preSaleTime之后的第一个?的位置
if (idx != unsure.end()) {
unsure.erase(idx);
} else {
// 如果没有?可以用,那么就是错误情况了
if (ans == -1) {
ans = i;
}
}
}
sale_time[number] = i;
}
}
}
printf("%d\n", ans);
}
return 0;
}

美团codeM之美团代金券的更多相关文章

  1. LOJ #6192. 「美团 CodeM 复赛」城市网络 (树上倍增)

    #6192. 「美团 CodeM 复赛」城市网络 内存限制:64 MiB 时间限制:500 ms 标准输入输出   题目描述 有一个树状的城市网络(即 nnn 个城市由 n−1n-1n−1 条道路连接 ...

  2. #6164. 「美团 CodeM 初赛 Round A」数列互质-莫队

    #6164. 「美团 CodeM 初赛 Round A」数列互质 思路 : 对这个题来言,莫队可以 n*根号n 离线处理出各个数出现个的次数 ,同时可以得到每个次数出现的次数 , 但是还要处理有多少 ...

  3. LibreOJ #6192. 「美团 CodeM 复赛」城市网络

    #6192. 「美团 CodeM 复赛」城市网络 内存限制:64 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: sqc 提交提交记录统计讨论测试数据   题目描 ...

  4. 美团 CodeM 复赛」城市网络

    美团 CodeM 复赛」城市网络 内存限制:64 MiB时间限制:500 ms标准输入输出 题目描述 有一个树状的城市网络(即 nnn 个城市由 n−1n-1n−1 条道路连接的连通图),首都为 11 ...

  5. [LOJ 6213]「美团 CodeM 决赛」radar

    [LOJ 6213]「美团 CodeM 决赛」radar 题意 给定 \(n\) 个横坐标 \(x_i\) , 为它们选择一个不超过 \(y_i\) 的纵坐标 \(h_i\), 产生 \(c_ih_i ...

  6. LibreOJ #6191. 「美团 CodeM 复赛」配对游戏

    二次联通门 : LibreOJ #6191. 「美团 CodeM 复赛」配对游戏 /* LibreOJ #6191. 「美团 CodeM 复赛」配对游戏 概率dp */ #include <cs ...

  7. LibreOJ #6212. 「美团 CodeM 决赛」melon

    二次联通门 : LibreOJ #6212. 「美团 CodeM 决赛」melon /* LibreOJ #6212. 「美团 CodeM 决赛」melon MDZZ 这是决赛题?? */ #incl ...

  8. 「题解」「美团 CodeM 资格赛」跳格子

    目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞 ...

  9. 【¥200代金券、iPad等您来拿】 阿里云9大产品免费公测#10月9日-11月6日#

    #10.09-11.06#200元代金券.iPad大奖, 9大产品评测活动! 亲爱的阿里云小伙伴们: 云产品的多样性(更多的云产品)也是让用户深度使用云计算的关键.今年阿里云产品线越来越丰富,小云搜罗 ...

随机推荐

  1. == 和 equals 的区别是什么?

    已经有很多人说过二者的区别了,我直接上代码. String strA = "123"; String strB = "123"; String strC = & ...

  2. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 78,050,512 milliseconds ago.

    今天访问已经架上服务器的网站,报错: Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet s ...

  3. Log4j简单配置解析

    log4j.rootLogger=ERROR, stdoutlog4j.logger.tk.mybatis.simple.mapper=TRACElog4j.appender.stdout=org.a ...

  4. Vmware vSphere 开启嵌套虚拟化

    一.vSphere 6开启嵌套虚拟化 已通过vSphere Client创建一个名字为Centos 7的虚拟机,现在需要打开该虚拟机的嵌套虚拟化功能. 1.在Esxi 服务器上面开启ssh服务,并关闭 ...

  5. 字幕字体滚动插件——scroxt.js

    README scroxt.js Overview scroxt.js是一个字体滚动的插件库,包括视频弹幕滚动,直播弹幕.直播弹幕强制模式.单行水平左右滚动.文本垂直滚动上下,用于简单快捷生成滚动字体 ...

  6. Java程序设计实验 实验五

    课程:Java程序设计实验   班级:1353  姓名:符余佳源  学号:20135321 成绩:                           指导教师:娄嘉鹏      实验日期:2015. ...

  7. spring冲刺第五天

    昨天进行了地图的初步编写,上网查找了错误的原因,改进了源代码,使程序可以执行. 今天继续编写地图代码,完善地图界面,使其变得美观. 遇到的问题:地图的完善比较难.

  8. 再学HTML之一

    Html 超文本标记语言 什么是html? HTML 是用来描述网页的一种语言. HTML 指的是超文本标记语言 (Hyper Text Markup Language) HTML 不是一种编程语言, ...

  9. In-band Network Function Telemetry

    文章名称:In-band Network Function Telemetry 发表时间:2018 期刊来源:SIGCOMM I Introduction (介绍) NFV运行在商品服务器上,在网络功 ...

  10. b4

    吴晓晖(组长) 过去两天完成了哪些任务 昨天FloatingActionButton和权限获取调整 今天复习,没写东西,晚点有空了写 展示GitHub当日代码/文档签入记录 接下来的计划 推荐算法 还 ...