A-统计线段

对于每一个点,我们暴力的统计有多少线段左端在它左边,右端在他右边,可以用两个for循环写出来,那么此时的复杂度是\(O(NM)\),可以通过\(80\%\)的数据。

但是对于全部的数据来说,点和线段的数目都达到了\(10^5\),此时如果还是用之前的方法,那么总的复杂度将会达到\(10^{10}\),这是不能接受的。

于是我们可以考虑分开统计线段的左端和右端,将所有线段的左端和右端存到两个数组里面去。对于每个点,分别在左端和右端两个数组中进行二分,假设分别得到有L个线段左端大与等于该坐标点,R个线段右端小于该坐标点,而(L-R)就是我们要的答案,总的复杂度为\(O(Nlog_2M)\)

B-快乐早八

大模拟题目,说实话,这是本场最考验代码能力的题目,对完成的同学respect,因为实在是有点毒瘤了

这里提供一个思路,就是从后往前开始枚举起床时间,然后第一个能够按时到达教室的时间就是我们要的答案。

C-幸运因子

本题需要将题目给的意思转换一下:

1.如何来统计路径上的元素之积能够被6整除多少次呢?
首先我们可以发现数字2和3都是6的质因子,所以只要我们计算出路径上每个元素能够整除2和3多少次,然后将两个数字的总和取一个最小值,就是我们需要的答案。

2.如何来选择合适的路径呢?
首先,根据题目的意思,直线路径是比不上能够转弯的路径的,毕竟我们可以在直线路径的端点处调头嘛,因此目标的路径一定是一个转弯的的路径。但是路径只能转一次弯,我们可以枚举矩阵上的每个点作为路径转弯点。对于每个转弯点来说,总共有四个方向,四种组合,分别是左上,左下,右上,右下,我们只需要统计这四种情况下的各自的答案,然后取一个最大的作为最终答案就行了。
思路已经有了,现在看如何实现。

对于每个点来说,如果暴力的用循环统计总和,那么每个点都要统计\(O(N)\)次,点的数量总共是\(O(N^2)\),所以整体复杂度就要到\(O(N^3)\),此时可以通过\(50\%\)的数据了。
要想获得后面的分数,就必须要对每个点的统计进行优化,此时我们可以进行数据的预处理,用数组分别将从左往右遍历和从上往下遍历的元素之积能够被2和3整除的次数算出来,累加到前缀和数组中,这样子对于每个点就不必去每次遍历上下左右四个方向,直接用前缀和数组计算一下就行了。此时整体复杂度降到了\(O(N^2)\),可以通过。

D-最多的1

很容易想到最最最暴力的写法,直接遍历每个点作为矩阵的右下端点,然后再枚举矩阵的长宽,最后再统计矩阵当中的每个元素是否符合要求,此时的复杂度应该是\(O(N^6)\)可怕的复杂度

优化一下,假设从上往下一层一层地统计矩形,对于当前层每一个元素,都用一个数组h来储存它和上方连续的数字1的数量。对于每一层的第\(i\)个元素来说,当它为数字0时\(h_i\)为0,否则为上一层的\(h_i+1\)。对于每一个\(h_i\)来说,它对答案的贡献是多少呢,我们需要找到这个数组左端第一个小于它的\(h_l\),右端第一个小于它的元素\(h_r\),此时答案就是\((r-l-1)*h_i\)。假设我们暴力地去统计这个左端和右端,那么对于每个\(h_i\)来说,复杂度是\(O(N)\),整体复杂度是\(O(N^3)\)

再优化一下,其实寻找\(h_i\)贡献的过程是一个经典的问题,我们可以在遍历\(h_i\)贡献的时候用一个单调栈来储存\(h_i\)元素,单调栈中必须保证栈顶元素要小于当前遍历到的\(h_i\),否则就弹出栈,直接计算它的贡献,假设栈顶元素位置是\(k\),而它的贡献是多少呢,就是\((当前遍历到的位置i-栈顶新的元素所处的位置stk[top]-1)*h_k\),这就是我们上面要求的对于\(h_k\)的L和R,在完成一次遍历之后,我们也就求得了想要的答案,此时整体复杂度是\(O(N^2)\)

E-结点种类

首先我们通过数字来取代原来结点上的字符串的值,否则难以进入进行下一步的运算,用2进制每一位是否为1来表示该大小的字母在原字符串中是否存在,如"AC"用数字5来表示,它的二进制表达式为"101",之后我们都用数字来代指原来的字符串。

本题有两种思路

先讲一下bfs(广度优先搜索)的写法:
首先对于每一个数字A,和他相似的元素B只有两种情况:

  1. 二进制表达式中A刚好只有一位和B不一样,比如“101”和“100”
  2. 二进制表达式中有一数位A为1,B为0,同时另有一数位A为0,B为1,比如“101”和“110”

所以对于每一个数字来说,我们可以通过枚举二进制位数的方式,来找到和它相似的所有数字。此时我们可以使用bfs的方式,将和当前数字相似且是结点元素的数字全部找出来,如果这个结点还没有进入过队列,那么我们就让它进入队列,每次bfs结束的时候,我们就找到了一个种类的所有元素。

此方法复杂度为\(O(N*26^2)\)

之后再说一下如何使用并查集来写:
还是对于每个数字来说,搜索所有和它相似的元素,如果不在一个集合,就将它们两个进行合并。
之后遍历每个元素,看它的父亲是否实自己,如果是的话那么就找到了一个新的类,统计进入答案。
复杂度\(O(N*log_2N*26^2)\)