Google Kickstart 2019 刷题笔记

本文深入解析了2019年多个算法竞赛题目,涵盖了从简单到复杂的多种算法策略,包括快速幂法、动态规划、计算几何、差分区间和、质数判断、贪心法等,为参赛者提供了宝贵的解题思路。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

Practice Round 2019

1. Number Guessing

  • 水题,略过

2. Mural

  • 基于如下事实:只要你想,你可以保住任何一段长为⌈N/2⌉\lceil N/2 \rceilN/2的墙,故只要求和最大的一段墙即可

3. Kickstart Alarm

  • 本题的精髓是如何快速求a1+a2+...+ana^1+a^2+...+a^na1+a2+...+an;类似于快速求幂法,只是要同时维护两个变量a1+a2+...+aia^1+a^2+...+a^ia1+a2+...+aiaia^iai

Round A 2019

1. Training

  • 排序之后用窗口扫描即可;结果我用Go写第二问就超时,用C写就过了,可能是Go的IO效率低?

2. Parcels

  • 本题涉及计算几何的经典问题:给定 NNN 个点,如何用 O(N)O(N)O(N) 时间求出其中最大的曼哈顿距离?(或给定 NNN 个点,预处理后,如何用 O(1)O(1)O(1) 时间求出新的一个点到其中最大的曼哈顿距离?)
  • 上面的问题解决后,就可以用二分猜测法,每次用 O(RC)O(RC)O(RC) 时间扫描全盘来验证,总用时 O(RC⋅log(R+C))O(RC\cdot log(R+C))O(RClog(R+C))
  • 注意到若一个点可以实现最小距离 kkk,那么与它相邻的点可以实现的最小距离一定为 k−1k-1k1kkkk+1k+1k+1 之一;故我们甚至没有必要进行二分猜测,只要全盘扫描一遍,记录找到的最小距离即可,总用时 O(RC)O(RC)O(RC)

3. Contention

  • 基于如下事实:由于每次新覆盖的区域与之前的覆盖顺序无关,故为使每次新覆盖区域的最小值最大,必须使最后一次的区间新覆盖的区域尽可能大
  • 这里倒着解答,每次取出新覆盖区域最大的区间,本人只看懂了每次用O(N)O(N)O(N)扫一遍的方法,总用时O(N2)O(N^2)O(N2)

Round B 2019

1. Building Palindromes

  • 区间求和,判断数量为奇数的字母个数是否不超过1即可;由于不需要求每个字母的具体数量,所以可以用位运算异或来减少运算量
  • 一看到区间求和我就上了树状数组,后来意识到这些字母并不会更新,所以可以用前缀和达到O(N)O(N)O(N)的复杂度

2. Energy Stones

  • 基于如下事实:若两块石头 iiijjj 会被吃,且 SiLj<SjLiS_iL_j<S_jL_iSiLj<SjLi,则 iii 一定先于 jjj 被吃;根据该事实进行排序,然后确定每块石头是否被吃即可
  • 用动态规划,比较特别的是这是一个“我为人人”的动规,即用 max_energy(i,t)max\_energy(i, t)max_energy(i,t) 更新 max_energy(i+1,t)max\_energy(i+1, t)max_energy(i+1,t)max_energy(i+1,t+time[i])max\_energy(i+1, t+time[i])max_energy(i+1,t+time[i]) 的最大值

3. Diverse Subarray

  • 本题的精髓是使用差分的区间和来计算该区间上可以带的礼物的最大值,于是遍历所有左端点,求出右边区间的最大前缀和即可
  • 这里用树状数组来做到单点更新和区间求最大前缀和,另外需要一个哈希链表来记录下一个被更新的点在哪里

Round C 2019

1. Wiggle Walk

  • 一开始我也想到用某种办法一次性跨过之前走过的方块,奈何一下子想不出合适的数据结构,不得已看了解析,原来就是用STL的map存储区间

2. Circuit Board

  • 如果熟练的话,本题应该能看出来这是直方图最大矩形的衍生问题;看出来之后从左到右用竖线做底扫一遍即可
  • 做第2问的时候没注意multiseterase的语义,移除元素xxx之一应该写ms.erase(ms.find(x)),否则就是移除全部xxx

3. Catch Some

  • 先假设最后一次也要回家,设min_step(i,j)min\_step(i, j)min_step(i,j)为使用前i种颜色访问j只狗所需的最小步数,则min_step(i,j)=min(min_step(i−1,j−k)+sum(i,k))min\_step(i, j)=min(min\_step(i-1, j-k)+sum(i, k))min_step(i,j)=min(min_step(i1,jk)+sum(i,k)),其中sum(i,k)sum(i,k)sum(i,k)是第i种颜色第k只狗的距离
  • 为了使最后一次区别对待,需要用两个数组min_step_all_homed(i,j)min\_step\_all\_homed(i, j)min_step_all_homed(i,j)min_step_once_unhomed(i,j)min\_step\_once\_unhomed(i, j)min_step_once_unhomed(i,j),这样最小答案就在后者里

Round D 2019

1. X or What?

  • 基于如下事实:合法区间必为 xor-even 数的个数为偶数的区间,而最大区间至少有一边在数组的端点,这样每次只需回答一个判断题,即取左端点还是右端点

2. Latest Guests

  • 这题要是改成所有人都朝一个方向转就简单了,而考虑两个方向时只需要一个小技巧,就是在记录每户最后到访者时顺便记下时间,然后比较两个方向哪个更新即可

3. Food Stalls

  • 这题和简单选点问题不同的是加上了距离代价,和上题有点相似的是,如果假设仓库必须建在所有商店的右边,那么就可以用绝对距离计算代价,然后用大小为KKK的最大值堆从左到右扫一遍,留下的KKK个点即是KKK个商店
  • 由直线上多点距离之和的性质得,仓库必须建在K+1K+1K+1个点的中点上,故先在左边建⌊K/2⌋\lfloor K/2 \rfloorK/2个商店,再在右边建⌈K/2⌉\lceil K/2 \rceilK/2个商店,最后求加在一起的最小值即可
  • 有个坑就是xxxccc都特别大,要开long long才能解决,下次要注意看题

Round E 2019

1. Cherries Mesh

  • 简单图问题,设用黑线连在一起的为一组,则答案为N+G−2N+G-2N+G2,其中NNN为总点数,GGG为总组数

2. Code-Eat Switcher

  • code/eatcode/eatcode/eat排序,大的放前面,每次优先将前面的codecodecode时间占满,然后在满足总codecodecode时间的情况下剩余的eateateat时间一定最大
  • 这题在边界判断上卡了很久,最后自己造数据才发现问题,还有又踩了一次long long的坑

3. Street Checkers

  • 先考虑每个单独的XXX,设XXX可以分解质因数为X=2n⋅a1m1⋅a2m2⋅...X=2^n\cdot a_1^{m_1}\cdot a_2^{m_2}\cdot ...X=2na1m1a2m2...,则XXX符合条件等价于:
    • n=0n=0n=0XXX是质数(或111
    • n=1n=1n=1
    • n=2n=2n=2X/4X/4X/4是质数(或111
    • X=8X=8X=8
  • 然后就是怎么判断质数的问题了,由于X≤109X\le 10^9X109,故可以用XXX除以222109\sqrt{10^9}109之间的质数来判断,这之间有340134013401个质数,虽然我觉得复杂度挺高但还是过了

Round F 2019

1. Flattening

  • 这题属于容易做也容易错的题,方法很简单,就是用动态规划,从左到右扫一遍,并且动态更新min_rebuild(last_height,changes)min\_rebuild(last\_height, changes)min_rebuild(last_height,changes)数组,复杂度O(N3)O(N^3)O(N3)还是绰绰有余的
  • 我一开始错就错在试图节约last_heightlast\_heightlast_height的初始数量,因为后面的高度可能会影响前面的高度,所以必须一开始就把所有高度加入状态集中

2. Teach Me

  • 我一开始想的是计算iii不能教的人,但这样显然不能简化为子集查询的问题;应该是计算不能教iii的人,这样只要查询与iii的某个子集相同的人数
  • 之所以能用子集查询是因为每个人最多有555个技能,且总技能数不超过100010001000,所以可以用long long作为任意子集的key

3. Spectating Villages

  • 我想的和答案一样,都是看成树然后动态规划,但我觉得我的简单些(答案的动态规划套了娃)
  • 维护三个最大值lighted_by_itselflighted\_by\_itselflighted_by_itselflighted_by_childrenlighted\_by\_childrenlighted_by_childrenunlightedunlightedunlighted,第二个值需要注意,因为如果在所有子节点都灭灯的时候取到最大值,必须强行让一个子节点亮灯

Round G 2019

1. Book Reading

  • 这题刚看到的时候被吓到了,因为想着O((105)2)O((10^5)^2)O((105)2)肯定超时,然后看了下答案,原来并没有那么复杂,虽然对于小的数统计一遍要O(105)O(10^5)O(105),但从大的范围看,全部统计一遍的复杂度为O(N1+N2+...+NN)≈NlogNO(\frac{N}{1}+\frac{N}{2}+...+\frac{N}{N})\approx NlogNO(1N+2N+...+NN)NlogN,所以只要打个表再查就行

2. The Equation

  • 按位来分析,k的每个位会使A数组的每个位翻转,所以会使得SUMSUMSUM增大或减小
  • 由于要使k最大,所以只需用贪心法,先将会减少的位设为1,然后从最高位开始,只要翻转之后不超过SUMSUMSUM就设为1

3. Shift

  • 这题算是枚举优化的模板题了,基本的方法还是枚举,但这样会产生O(3k)O(3^k)O(3k)个结果,即使用了剪枝也过不了第二问
  • 枚举的问题在于,有多少个结果它就枚举了多少次,然而我们不需要真的每一个结果,只需要计算数量就行,所以如果能批量计算就好了
  • 答案的方法是将序列拆成两半AAABBB,分别枚举,然后统计对于每个aia_iai,有多少个bib_ibi符合要求;为了加快速度,这里用了排序和区间树,本质上将O((3N/2)2)O((3^{N/2})^2)O((3N/2)2)的交互复杂度变为了O(3N/2log(3N/2))O(3^{N/2}log(3^{N/2}))O(3N/2log(3N/2))

Round H 2019

1. H-index

  • 这题我想着用区间数肯定能做,但是第一题就用高级数据结构会不会想偏了,看了看答案,原来是用最小堆,由于H=min(q.top(),q.size())H=min(q.top(), q.size())H=min(q.top(),q.size()),而q.size()q.size()q.size()不会增加,所以如果q.top()<q.size()q.top()<q.size()q.top()<q.size()就不断弹出,最后的结果即是当前的HHH

2. Diagonal Puzzle

  • 这题需要一点数学观察,同时也非常复杂(写了150+行),首先如何翻转肯定是有约束的,比如:每条线至多翻转1次,白点能且只能翻转1次,黑点只能翻转0或2次
  • 但是最神奇的约束是,只要确定了两条大对角线(奇数时另一条对角线取第二长的,因为不能交叉于一格)有没有翻转,就可以确定剩下的所有翻转,因为这两条线的格点交叉的垂线覆盖了整张图
  • 总的步骤是:(1) 遍历两条大对角线的翻转情况(4种);(2) 确定两条线格点交叉的垂线的翻转情况;(3) 确定所有非上述线的翻转情况

3. Elevanagram

  • 这题对数学的要求太高了,也许这种整除题都有些套路,如何证明就不细究了,判断步骤为:(1) 如果有2个数都多于10个则真;(2) 如果有3个数都多于6个则真;(3) 遍历所有的组合情况,最坏时间复杂度的情况如下
5 5 5 5 5 5 5 9 99956
  • 但实际上最后一个数不会被遍历99956次,因为正负各占一半,所以它的取法完全由前面的取法决定,最坏复杂度为O(67×10)O(6^7\times 10)O(67×10)

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值