最近完成的一些算法题

一个多月没写博客了,赶紧填个坑。

kickstart

kickstart


离上一篇博客居然已经过去一个多月啦,看来研究生还是要比本科忙多了,每天都有事情要做。最近呢,就是参加了昨天的Google Kickstart Round G 2018,本来顺利做完了2.5题,做完的时候有60名左右,结果有个大数据犯了一个低级错误,结果一个大数据挂了,最后只有100多名!啊!好气啊!看了一下题解,发现方法和我自己实现的方法差挺多的,所以想简单讲一下我的算法。

Problem A. Product Triplets

这道题,就是给你一个序列An,n7000,让你计算满足Ai,Aj,Ak三个数中任意两个数乘积等于第三个数的这样的(i,j,k),i<j<k三元组的个数。

题解中给出的方法是使用HashSet存入每个数,同样也可以使用二分。注意到序列的顺序无关,因此我们可以先将数列排序,然后枚举i和j,注意到在绝大多数情况下,AiAjAi,Aj。因此我们要找的乘积一定在AiAj的右边,而由于整个序列是有序的,因此我们可以通过二分来快速找到相应的值,伪代码如下所示。

1
2
3
4
for i = 1 to n
for j = i + 1 to n
binary_search A[i] * A[j] from A[j + 1] to A[n]
answer ← answer + count(A[i] * A[j])

由于我们需要求出序列中AiAj的个数,因此在C++中,可以分别调用lower_boundupper_bound来求出上界和下界,然后相减即可求出个数。

前面提到在大多数情况下AiAjAi,Aj是成立的,那么是否有不成立的情况呢?有的,在Ai=0或者Aj=0的时候等式就不成立了。这个时候三元组对应的序列就变成了(0,0,Ak)。因此在排好序的序列中,我们需要特判AiAj都等于0的情况,可以计算得出此时三元组的个数恰好为序列中所有在Aj右边的元素的个数。也就是nj。整个算法的复杂度为O(n2logn)

Problem B. Combining Classes

这道题,是给你N[Li,Ri]连续区间组成的分数,然后有Q个查询,问这些区间中所有数字组成的序列的第Ki大的分数是多少,其中NQ的范围都在5105级别。

题解的方法是离散化+线段树区间维护,似乎有一些麻烦。实际上可以直接将区间拆成2N个点,然后从大到小排序。接下来就是处理区间端点的问题了,再遍历断点的过程中,我们需要一个变量cur用于记录当前分数有多少个人同分,sum记录目前总共排好了多少个人,这样在遍历的过程中不断的将Kisum进行比较就可以了。另外需要注意的是,在遍历过程中如果端点的发生了跳跃,我们需要直接算出Ki对应的分数,方法就是计算sumKi的差值,然后整除cur即可。整个算法中,排序复杂度是O(NlogN+QlogQ),遍历的复杂度是O(N+Q)

最近完成的一些算法题

https://kaitohh.com/oj-1/

作者

KaitoHH

发布于

2018-10-22

更新于

2018-10-22

许可协议

次转发
wechat-white sharing button 分享
qzone-white sharing button 分享
weibo-white sharing button 分享
facebook-white sharing button 分享
twitter-white sharing button 发推
email-white sharing button 电子邮件
sharethis-white sharing button 分享

评论

你可能无法访问 Disqus,已启用评论基础模式。如需完整体验请针对 disq.us | disquscdn.com | disqus.com 启用代理并 尝试完整 Disqus 模式 | 强制完整 Disqus 模式

    这里冷冷清清的,一条评论都没有

加载更多评论