首页 > 代码库 > CodeM美团点评编程竞赛资格赛题

CodeM美团点评编程竞赛资格赛题

最近看到牛课网美团一个编程竞赛,想着做做看,结果一写就是两天。。真是写不动了啊。话不多说,下面开始我的题解。

题目大致还是比较考察思维和代码能力(因为自己代码能力较弱,才会觉得比较考察代码能力吧= =!),难度由简到难变化也比较适中,有签到题、有算法实现,当然也有稍稍一点代码量的题。感谢美团点评,提供一套合适的题目~

音乐研究
题目描述
美团外卖的品牌代言人袋鼠先生最近正在进行音乐研究。他有两段音频,每段音频是一个表示音高的序列。现在袋鼠先生想要在第二段音频中找出与第一段音频最相近的部分。
具体地说,就是在第二段音频中找到一个长度和第一段音频相等且是连续的子序列,使得它们的 difference 最小。两段等长音频的 difference 定义为:
difference = SUM(a[i] - b[i])2 (1 ≤ i ≤ n),其中SUM()表示求和 
其中 n 表示序列长度,a[i], b[i]分别表示两段音频的音高。现在袋鼠先生想要知道,difference的最小值是多少?数据保证第一段音频的长度小于等于第二段音频的长度。
输入描述:
第一行一个整数n(1 ≤ n ≤ 1000),表示第一段音频的长度。
第二行n个整数表示第一段音频的音高(0 ≤ 音高 ≤ 1000)。
第三行一个整数m(1 ≤ n ≤ m ≤ 1000),表示第二段音频的长度。
第四行m个整数表示第二段音频的音高(0 ≤ 音高 ≤ 1000)。
输出描述:
输出difference的最小值
输入例子:
2
1 2
4
3 1 2 4
输出例子:
0

题解:

签到题,n*m<1e6,直接暴力枚举第二个数组的起点即可,复杂度O(n*m)。

#include <iostream>
#include <cstdio>
#include <map>
#include <set>
#include <cstring>

using namespace std;

const int kMaxN = 1000 + 5;
int n, m, a1[kMaxN], a2[kMaxN];

int main(){
	//freopen("in.txt","r",stdin);
	cin >> n;
	for (int i = 1; i <= n; i ++)
        cin >> a1[i];
    cin >> m;
    for (int i = 1; i <= m; i ++)
        cin >> a2[i];
    int ans = 1e9;
    for (int i = 0; i <= m - n; i ++) {
        int sum = 0;
        for (int j = 1; j <= n; j ++)
            sum += (a1[j] - a2[i + j]) * (a1[j] - a2[i + j]);
        ans = min(ans, sum);
    }
    cout << ans << endl;
	return 0;
}

  

 

锦标赛

题目描述
组委会正在为美团点评CodeM大赛的决赛设计新赛制。
比赛有 n 个人参加(其中 n 为2的幂),每个参赛者根据资格赛和预赛、复赛的成绩,会有不同的积分。比赛采取锦标赛赛制,分轮次进行,设某一轮有 m 个人参加,那么参赛者会被分为 m/2 组,每组恰好 2 人,m/2 组的人分别厮杀。我们假定积分高的人肯定获胜,若积分一样,则随机产生获胜者。获胜者获得参加下一轮的资格,输的人被淘汰。重复这个过程,直至决出冠军。
现在请问,参赛者小美最多可以活到第几轮(初始为第0轮)?
输入描述:
第一行一个整数 n (1≤n≤ 2^20),表示参加比赛的总人数。
接下来 n 个数字(数字范围:-1000000…1000000),表示每个参赛者的积分。
小美是第一个参赛者。
输出描述:
小美最多参赛的轮次。
输入例子:
4
4 1 2 3
输出例子:
2

 题解:

这个也比较好容易想到,很容易可以想到当小美被淘汰时,所有其他人的分数都是严格大于小美的分数的。所以直接将小美安排和所有与她分数低的人比赛即可,因为分数高的一定赢,因此可以认为她淘汰的人和被他淘汰的人淘汰的人,这些人分数都小于等于小美。

因此答案就是log2(count(score <= score[0])) score[0]是小美的分数。

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

int main(){
	//freopen("1.in","r",stdin);
	int n,ans = 0,x0, x;
	cin >> n;
    for(int i = 0; i < n; i++){
        scanf("%d",&x);
        if(i == 0) x0 = x;
        ans += x <= x0;
    }
	cout << ((int)(log(ans * 1.0) / log(2.0))) << endl;
	return 0;
}

 

 

 优惠券

美团点评上有很多餐馆优惠券,用户可以在美团点评App上购买。每种优惠券有一个唯一的正整数编号。每个人可以拥有多张优惠券,但每种优惠券只能同时拥有至多一张。每种优惠券可以在使用之后继续购买。

当用户在相应餐馆就餐时,可以在餐馆使用优惠券进行消费。某人优惠券的购买和使用按照时间顺序逐行记录在一个日志文件中,运营人员会定期抽查日志文件看业务是否正确。业务正确的定义为:一个优惠券必须先被购买,然后才能被使用。

某次抽查时,发现有硬盘故障,历史日志中有部分行损坏,这些行的存在是已知的,但是行的内容读不出来。假设损坏的行可以是任意的优惠券的购买或者使用。

现在给一个日志文件,问这个日志文件是否正确。若有错,输出最早出现错误的那一行,即求出最大s,使得记录1到s-1满足要求;若没有错误,输出-1。

输入描述:
输入包含多组数据
m 分别表示 m (0 ≤ m ≤ 5 * 10^5) 条记录。
下面有m行,格式为:
I x (I为Input的缩写,表示购买优惠券x);
O x(O为Output的缩写,表示使用优惠券x);
? (表示这条记录不知道)。
这里x为正整数,且x ≤ 10^5 。
输出描述:
-1 或 x(1 ≤ x ≤ m) 其中x为使得1到x-1这些记录合法的最大行号。
输入例子:
0
1
O 1
2
?
O 1
3
I 1
?
O 1
2
I 2
O 1

输出例子:
-1
1
-1
-1
2

 题解:

刚开始看到这题,就理所应当的认为只需要记录未知记录的个数,和每个优惠券的状态即可,如果在购买时发现还存在这种优惠券,就用未知记录代替,位置记录条数减一(消费同理)。

这样做的确是把不合理的购买或者消费记录给清楚了,但是这样做法的一个最大问题就在于,它没有考虑购买的时机,即认为未知记录是万能的。但是例如连续两次买进同一种优惠券(中间没有位置记录),这样也是不合法的。因此,我们需要分情况讨论:

购买优惠券x时:

  1.若之前没有交易过优惠券x或之前最后一次操作x已经将其卖出:  直接购买

    2.前一次操作是买入优惠券x:

    1)两次买进之间没有未知记录: 这条记录是不合法的

    2)两次买进之间有多次(>=1)条未知记录: 取最早的一条未知记录充当x的使用记录。

使用优惠券x时:

  1.之前对x的操作最后一次是买入优惠券x: 直接使用

    2.前一次对x的操作是对x的使用(或没有对x的操作记录):  

    1)找出这两次使用操作的最早的一条未知记录,充当买入操作

    2)若没有未知记录,这条记录不合法

上面为什么一定要取多天未知记录的最早的一条,读者自己可以思考下。下面我的代码用yhq变量保存最近的上一次操作优惠券x的位置,使用set集合来存放所有未知记录出现的位置(可以很方便的使用lower_bound函数)。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <map>
 4 #include <set>
 5 #include <cstring>
 6 
 7 using namespace std;
 8 
 9 char c;
10 int n, x;
11 map<int, int> yhq;
12 set<int> unknown;
13 
14 int main(){
15     //freopen("in.txt","r",stdin);
16     while(~scanf("%d%*c", &n)) {
17         yhq.clear();
18         unknown.clear();
19         int has_error = -1;
20         for (int i = 1; i <= n; i ++) {
21             scanf("%c%*c", &c);
22             if(c == ?) {
23                 unknown.insert(i);
24                 continue;
25             }
26             scanf("%d%*c", &x);
27             if(has_error >= 0) { // has find ans
28                 continue;
29             }
30             if(c == I) {
31                 if(yhq[x] > 0) {
32                     set<int>::iterator it = unknown.lower_bound(yhq[x]);
33                     if(it == unknown.end()) has_error = i;
34                     else unknown.erase(it);
35                 }
36                 yhq[x] = i;
37             }
38             else {
39                 if(yhq[x] <= 0) {
40                     set<int>::iterator it = unknown.lower_bound(-yhq[x]);
41                     if(it == unknown.end()) has_error = i;
42                     else unknown.erase(it);
43                 }
44                 yhq[x] = -i;
45             }
46         }
47         printf("%d\n", has_error);
48     }
49     return 0;
50 }

 

  

 

 

 

 

 

 

 




CodeM美团点评编程竞赛资格赛题