主题目
22 - 27 题
整体解析:
solve2可以比较简单的模拟,但是一时看不出来含义,solve1的算法类似筛法,p表示是否质数,k是i的幂次数组,f存的是最小质因数,g存的是满足最小质因数的最高幂次的因数。
f[i]= f[i / g[i]]*(g[i]* f[i]- 1)/(f[i]- 1); 是最难理解的一句。
首先 f[i/g[i]],因为i/g[i]<i,所以这个f[i/g[i]] 已经是经过计算的新的值。类似动态规划中数组的复用。
(g[i]*f[i]-1)/(f[i]-1),有点像等比数列求和公式,实际上求的是1,f[i],f[i]*f[i],...,g[i]这个数列的和。
如果能联想到求一个数的约数和的公式,可以理解完整的一行,实际上是在求i的所有约数和。sum是1-n的约数和的和。
28 - 33题
整体解析:
读f函数可知,f0中的a数组是从小到大排序的,a[j]<a[i]-m,j是小于a[i]-m的最后一个位置(或者0),所以s是计算序列a中差值不超过m的数对的个数。
f0判断满足这个条件的数对个数是否>=k。本题需要看懂题目才方便做题。
f函数是一个二分查找,g=0,h=a.back()-a[0],分别是条件最紧和条件最宽松,返回值是最小的x,满足a中差值不超过x的数对个数>=k。
34 - 38题
题目:
1、(第k小路径)给定一张n个点m条边的有向无环图,顶点编号从0到n-1。对于一条路径,我们定义'路径序列'为该路径从起点出发依次经过的顶点编号构成的序列。
求所有至少包含一个点的简单路径中,“路径序列'字典序第k小的路径。保证存在至少k条路径,上述参数满足1≤n,m≤105和1≤k≤1018。
在程序中,我们求出从每个点出发的路径数量。超过1018的数都用1018表示。然后我们根据k的值和每个顶点的路径数量,确定路径的起点,然后可以类似地依次求出路径中的每个点。
整体解析:
拓扑排序+动态规划,基本思路是先拓扑排序,然后按从后往前的顺序计算每个结点为起点的路径数,然后按编号排序找第k小路径的起点。
39 - 43题
题目 :
2、(最大值之和)给定整数序列ao,a₁,a₂……an,求该序列所有非空连续子序列的最大值之和。上述参数满足1≤n≤105和1≤ai≤108。
一个序列的非空连续子序列可以用两个下标I和r(其中0≤l≤r≤n)表示,对应的序列a1,a1+1,a1+2,……an。两个非空连续子序列不同,当且仅当下标不同。
例如,当原序列为[1,2,1,2] 时,要计算子序列[1],[2],[1],[2],[1,2],[2,1],[1,2],[1,2,1],[2,1,2],[1,2,1,2]的最大值之和,答案为18。注意[1,1]和[2,2]虽然是原序列的子序列,但不是连续子序列,所以不应该被计算。
另外,注意其中有一些值相同的子序列,但由于他们在原序列中的下标不同,属于不同的非空连续子序列,所以会被分别计算。解决该问题有许多算法,以下程序使用分治算法,时间复杂度是O(n log n)。
整体解析 :
分治算法,分为三部分来计算,1) 起点终点都在前半段;2) 都在后半段;3) 起点在前半段、终点在后半段。前两部分递归解决,难点在于第三部分。预处理后半段的两个数组,pre数组表示前缀数组的最大值(pre数组一定是单调不下降的),sum数组是pre数组前缀和。然后用双指针,前半段从后往前,维护最大值,后半段从前往后。
精选题目
答案及解析
23题:
答案:F,第一行是87,第二行是87,从这道题目,暗示了solve2和solve1解决的是同一个问题。实际上枚举了因数i,而i在1-n的数中贡献了n/i次。其实也是在计算1-n的约数和的和。
24题:
答案:T,按上题的理解,相同。
25题:
答案:D,埃式筛法的复杂度。
28题:
答案:T,二分的右边界可能会变成比满足条件的最小值小1的那个,也有可能这行没有执行到,一直g=m+1,则输出不变。
29题:
答案:T,h的最大值是2*10^8,换一个方式计算mid不会越界。
31题:
答案:C,sort的复杂度O(nlogn),二分部分的复杂度O(nlogA),加起来就是nlogn+nlogA=nlog(nA),这里A和n的数量级不清楚,不能简化。
32题:
答案:B,变成了差值小于x的数对个数,相当于判断条件变严格了,答案可能会变大或者不变。
33题:
答案:B,排序后是-12 -5 2 3 8,差值不超过14的数对是8,差值不超过13的数对是7。
36题:
答案:A,动态规划,计算u为起点的路径树,f[u]=1是只有自身的一条路,枚举所有子结点的路径数,累加。先把Q逆序是因为要拓扑序靠前的结点计算依赖拓扑序靠后的结点。
39题:
答案:D,std::vectorpre(a + mid, a+r); 复制从a[mid]到a[r-1]的数组。然后计算这个数组的前缀最大值,即pre[i]是从0到i的数组的最大值。
40题:
答案:B,找最大值在前半段还是后半段的分界点,比较容易混淆的是C选项,因为此时max还没有更新,所以不能让a[j]或pre[j-mid]跟max来比,只能跟a[i]来比。
42题:
答案:C,i为起点,终点在后半段,且最大值在后半段的情况,最大值的和通过sum前缀和数组计算。
43题:
答案:A,因为line 12-14行,可以看到二分的结束条件是l+1==r,而且此时取l的值,也就是说[l,r),左闭右开的区间。
最后的话
现在可以自己尝试着做一下哈!!!这可是真题呦!!!
最后的最后:
作者做这个耗费了太多脑细胞了,请——
制作不易,点个赞吧!!!
制作不易,点个赞吧!!!
制作不易,点个赞吧!!!