标签:题目 使用 i++ names 表示 ase err 代言 can
最近看到牛课网美团一个编程竞赛,想着做做看,结果一写就是两天。。真是写不动了啊。话不多说,下面开始我的题解。
题目大致还是比较考察思维和代码能力(因为自己代码能力较弱,才会觉得比较考察代码能力吧= =!),难度由简到难变化也比较适中,有签到题、有算法实现,当然也有稍稍一点代码量的题。感谢美团点评,提供一套合适的题目~
第一行一个整数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; }
锦标赛
第一行一个整数 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 }
标签:题目 使用 i++ names 表示 ase err 代言 can
原文地址:http://www.cnblogs.com/gj-Acit/p/7003075.html