A题. Collecting Coins
题意:有3个人,分别有a、b、c,枚硬币。现有n枚硬币,问是否可以把n枚硬币全部分给3个人,使得3个人的硬币总数均相同
思路:贪心地想,如果可以分配,那么就是每个人的最终硬币数量肯定均大于等于max(a,b,c)。这样,我们就可以看n - (3 * max(a, b, c) - (a + b + c))是否可以平均分配给3人(即%3);
AC代码
B. Collecting Packages
题意:一个二维平面内,有n个物体,其坐标均是整数。有一个机器人,起始位置在(0,0),只能右移以及上移。问是否有一条路径可以让机器人经过所有物体,如果不可以输出NO,否则输出YES。如果有多个路径,选择字典序最小的路径输出
思路:贪心地想,这n个物体利用x值划分,x值相同的化为一类,那我们就可以发现从一个类到另外一个类的条件是,y不递减。具体解释,例如有(2,3)(2,4)(2,5)(3,5)
第一类:(2,3)(2,4)(2,5)
第二类:(3,5)
我们其实只需要比较第一类的最后一个元素与第二类的第一个元素即可(比较其y值)
保证输出的答案字典序最小:我们就是能往R走就往右走
AC代码
C. Product of Three Numbers
题意:给你一个整数n,问你能否找到3个互不相同的整数a, b, c(均大于2),使其乘积abc = n
思路:我们考虑a < b < c,n的数据范围最大为1e9,那可以推测a的范围最大为1e3。所以我可以暴力枚举a的值,每次check(n / a)(n % a == 0时才需要check),check过程就类似于素数判断,check复杂度O(sqrt(n / a)),所以算法总复杂度t * 1e3 * sqrt(n / a)
AC代码
D. MEX maximizing
题意:给你一个x,q次询问。开始时,数组为空,每次询问往数组里加入元素,在下一次询问前,可以考虑对数组里面所有元素进行加x的整数倍操作,问每次操作后mex of array的答案(数组里面没有出现过的最小整数)
思路:贪心地想,每次询问之后,我要尽可能把小的数全部在数组出现,这样答案有效性成立。我们就可以用一个变量表示现在我需要的最小数,每次询问之后,看能不能把最小数利用操作弄出来,如果可以,最小数++,继续判断。否则输出这个最小数作为本次操作后的答案。问题就转化为当前桶里面有没有我需要的数,很简单,利用一个cnt【】数组,记录一下当前对答案无贡献的数的个数,考虑到每个数的范围很大,所以我们可以考虑%x进行存储(原因在于每次操作可以 +kx(k属于整数)),后面判断就很简单。
AC代码
E. Obtain a Permutation
题意:给你一个n * m的矩阵,每个方格都有一个数字。有两种操作,操作一:把a[i][j]替换成某一个数,操作二:选择一列进行shift操作(具体可以参照题目)。问你最少需要多少次操作,才可以把矩阵里面的元素转化为题目要求的(顺序)矩阵。
思路:对于每一列,最坏的情况是,对于每一列的元素均进行替换操作,那么操作数为n。继续观察发现,如果某一列中有几行元素,通过操作二可以同时移动到要求的位置,那我们就可能减少操作次数。所以我们可以枚举每一列的元素,用一个桶记录,每一个元素通过几次操作二可以移动到要求的位置。显然有些元素是不属于这一列的,所以我们需要写一个check函数,来检查这个数是不是在这一行,以及如果在这一行,应该在哪一个位置。
(1)首先在第j列,那么这个数%m == j
(2)这个数的范围为【j, (n - 1) * m + j】
(3)这个数应该在的行数为 row = (val(数) - j) / m + 1;
所以计算移动次数就可以用 (i - row + n) % n(这里 + n是为了避免负数,例如,当前数在第一行,但是它应该在第n行,那么只需要移动一次即可)
当我们统计完之后,就可以开始遍历这个桶cnt[i](移动i次的元素个数)
ans = min(ans, n - cnt[i] + i)(注意 n - cnt[i] 表示的是通过一操作变成我想要的元素, + i表示这cnt[i]个元素要进行i次操作二),那么这个ans就是这一列对答案的贡献
F. Three Paths on a Tree
题意:记way(a, b)为a到b的简单路径集合。给你一颗树,让你在树上找3个不同的点x, y, z,使得|way(x,y) 交 way(x, z) 交 way(y,z)|的值最大。
思路:看了一样,就立刻想到树的直径,然后check树直径上的点向外延伸的最大距离。(目前思路感觉是这样,具体证明你们可以参考别人的博客),细心发现ans = (dis(x, y) + dis(x, z) + dis(y,z)) / 2;所以我们可以用3次bfs解决改题。
第一次bfs求出树直径的一个端点u
第二次bfs求出树直径的另一个端点v(并记录每一个点到u的距离)
第三次bfs 从v进行(并记录每一个点到v的举例)
AC代码