前天做了下美团的一个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

解题思路

当时没有想明白具体的逻辑,改了很久都没有过,今天问小崔才明白正确的解题思路。经过分析之后我们知道,输入?的时候是肯定不会有错误的,错误只能出现在I与O的某行。那么当输入为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. 洛谷P1585 魔法阵

    题目传送门 这题就是一个有技巧的DFS+一大堆乱七八糟的剪枝 进行DFS时注意一下以下点 根据题意,我们可以把DFS分成两块,即1--n*m/2与n*m/2--n*m,第一块边找边记录,第二块就开始计 ...

  2. oracle数据库之rownum和rowid用法

    Rownum 和 Rowid是Oracle数据库所特有的,通过他们可以查询到指定行数范围内的数据记录.   以下通过例子讲解: -- 为了方便,首先,查找dept表中的所有. select deptn ...

  3. Spring入门学习笔记(2)——基于Java的配置

    目录 基于Java的配置 @Configuration & @Bean Annotations Example 注入Bean依赖 @Import注解 Lifecycle Callbacks(声 ...

  4. golang--性能测试和分析

    前言 测试分为:压力测试.负载测试.性能测试,功能测试等等,其中在开发过程中开发人员经常要写一些test case unit 自己的模块进行功能测试测和性能.在分析出模块的性能瓶颈后开发人员就需要针对 ...

  5. Vue的computed计算属性是如何实现的

    一个开始 有如下代码,full是一个计算属性,开始,他的值是'hello world',1s后,msg变成了‘I like’, full的值同步变成了'I like world';其原理解析来看一下. ...

  6. 如何获取启动页activity

    启动页activity指App启动的第一个activity,介绍几种查看启动页activity的方法: 方法一:问开发,最有效的获取方式 方法二:dumpsys package 包名,前提是知道包名( ...

  7. Codeforces Round #258 (Div. 2) 容斥+Lucas

    题目链接: http://codeforces.com/problemset/problem/451/E E. Devu and Flowers time limit per test4 second ...

  8. JAVA自学日记——Part Ⅲ

    终于来到了可视化窗口制作的部分了,从学习JAVA之前,到开始入手学习,一直到现在,都在盼望着有一天可以自己写出一款有界面而且是很美观的应用程序,今天算是一个真正开始的时间节点,值得纪念. 内容有很多, ...

  9. Linux网卡配置文件路径是什么?要使服务器上外网,必须满足的条件有哪些?需要配置什么?

    Linux网卡配置文件路径是什么?要使服务器上外网,必须满足的条件有哪些?需要配置什么?    答:    网卡配置文件路径:/etc/sysconfig/network-scripts/ifcfg- ...

  10. c++浅拷贝与深拷贝(LeetCode669)

    之前上C++/C#课上老师讲过这个问题,只不过当时主要是跟着老师的节奏与情形,从理论上基本了解了其原理.不过当自己写代码的时候,还是遇到了这个非常坑的问题.因此再来分析一下. 今天第一次做LeetCo ...