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

题目描述

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

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

  1. I 1
  2. O 1

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

如果消费记录是这样的:

  1. I 1
  2. I 1
  3. O 1

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

如果消费记录是这样的:

  1. ?
  2. I 1
  3. O 2

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

输入样例

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

  1. 2
  2. I 1
  3. O 1
  4. 3
  5. I 1
  6. I 1
  7. O 1
  8. 3
  9. ?
  10. I 1
  11. O 2
  12. 4
  13. I 1
  14. ?
  15. O 1
  16. O 1

输出样例

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

  1. -1
  2. 2
  3. -1
  4. 4

解题思路

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

解题代码

  1. #include <cstdio>
  2. #include <set>
  3. #include <cstring>
  4. using namespace std;
  5. const int maxn = 100000+10;
  6. int m, number;
  7. char type;
  8. int buy_time[maxn], sale_time[maxn];
  9. bool coupon[maxn];
  10. set<int> unsure;
  11. set<int>::iterator idx;
  12. int main() {
  13. while (~scanf("%d", &m)) {
  14. memset(buy_time, -1, sizeof(buy_time));
  15. memset(sale_time, -1, sizeof(sale_time));
  16. memset(coupon, false, sizeof(coupon));
  17. unsure.clear();
  18. int ans = -1;
  19. for (int i = 1; i <= m; ++i) {
  20. getchar();
  21. scanf("%c", &type);
  22. if (type == '?') {
  23. unsure.insert(i);
  24. } else {
  25. scanf("%d", &number);
  26. if (type == 'I') {
  27. if (!coupon[number]) {
  28. coupon[number] = true;
  29. } else {
  30. // 对处于上一个I与现在这个I之间的第一个?做一个处理,将它作为一个O使用
  31. int preBuyTime = buy_time[number];
  32. idx = unsure.lower_bound(preBuyTime); // 返回preBuyTime之后的第一个?的位置
  33. if (idx != unsure.end()) {
  34. unsure.erase(idx);
  35. } else {
  36. // 如果没有?可以用,那么就是错误情况了
  37. if (ans == -1) {
  38. ans = i;
  39. }
  40. }
  41. }
  42. buy_time[number] = i;
  43. } else {
  44. if (coupon[number]) {
  45. coupon[number] = false;
  46. } else {
  47. // 对处于上一个O与现在这个O之间的第一个?做一个处理,将它作为一个I使用
  48. int preSaleTime = sale_time[number];
  49. idx = unsure.lower_bound(preSaleTime); // 返回preSaleTime之后的第一个?的位置
  50. if (idx != unsure.end()) {
  51. unsure.erase(idx);
  52. } else {
  53. // 如果没有?可以用,那么就是错误情况了
  54. if (ans == -1) {
  55. ans = i;
  56. }
  57. }
  58. }
  59. sale_time[number] = i;
  60. }
  61. }
  62. }
  63. printf("%d\n", ans);
  64. }
  65. return 0;
  66. }

美团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. 三种UIScrollView嵌套实现方案

    背景 随着产品功能不断的迭代,总会有需求希望在保证不影响其他区域功能的前提下,在某一区域实现根据选择器切换不同的内容显示. 苹果并不推荐嵌套滚动视图,如果直接添加的话,就会出现下图这种情况,手势的冲突 ...

  2. docker run 和docker start的区别

    docker run 只在第一次运行时使用,将镜像放到容器中,以后再次启动这个容器时,只需要使用命令docker start 即可. docker run相当于执行了两步操作:将镜像放入容器中(doc ...

  3. 匹配追踪算法(MP)简介

    图像的稀疏表征 分割原始图像为若干个\[\sqrt{n} \times \sqrt{n}\]的块. 这些图像块就是样本集合中的单个样本\(y = \mathbb{R}^n\). 在固定的字典上稀疏分解 ...

  4. Python遗传算法工具箱DEAP框架分析

    本文主要介绍python遗传算法工具箱DEAP的实现.先介绍deap的如何使用,再深入介绍deap的框架实现,以及遗传算法的各种实现算法. 代码可以参考 https://github.com/suma ...

  5. 高可用OpenStack(Queen版)集群-1. 集群环境

    参考文档: Install-guide:https://docs.openstack.org/install-guide/ OpenStack High Availability Guide:http ...

  6. Mac下基于testrpc和truffle的以太坊智能合约开发环境搭建

    原文地址:石匠的blog truffle是一个基于Javascript开发的一套智能合约开发框架,使用Solidity语言编写合约.truffle有一套自动的项目构建机制,集成了开发,测试和部署的各个 ...

  7. rename命令详解

    基础命令学习目录首页 原文链接:http://man.linuxde.net/rename 将main1.c重命名为main.c rename main1.c main.c main1.c renam ...

  8. Scrum Meeting 10.24

    成员 已完成任务 下一阶段任务 用时 徐越 阅读后端代码,了解服务器的概念,以及服务器和终端间的通信机制 学习服务器配置 4h 赵庶宏 阅读后端代码,了解服务器的概念,以及服务器和终端间的通信机制 阅 ...

  9. [BUAA_SE_2017]结对项目-数独程序扩展

    结对项目-数独程序扩展 Runnable on x64 Only sudoku17.txt 须放置在可执行文件同目录中,可移步以下链接进行下载 Core-Github项目地址 GUI-Github项目 ...

  10. 2018-2019-20172329 《Java软件结构与数据结构》第九周学习总结

    2018-2019-20172329 <Java软件结构与数据结构>第九周学习总结 教材学习内容总结 <Java软件结构与数据结构>第十五章-图 一.图及无向图 1.图的相关概 ...