复盘|第358场周赛
数组中的最大数对和
【一次遍历】用一个长为10的数组max_val维护最大数位为i的元素的最大值,当遍历到nums[i]时,设其最大数位为max_d,用nums[i] + max_val[max_d]更新答案。
翻倍以链表形式表示的数字
【一次遍历】如果不考虑进位,cur.val会变成cur.val * 2 % 10,如果cur.next有进位,那么cur.val需要+=1。如果链表头的值≥5,那么需要在前面加一个新节点。
限制条件下元素之间的最小绝对差
【平衡树 + 双指针 + 二分】对于每个位置i,只需将其与[0, i - x]的数值相比较,遍历nums是,维护一个有序数组,包含nums中[0, i - x]的元素,通过二分查找到nums[i]插入位置,与相邻位置作比较。有序数组初始化时可以放两个哨兵。
操作使得分最大
【贡献法 + 单调栈 】贪心思想,先考虑nums中最大的元素x,需要知道有多少个子数组可以取x作为质数分数最高的元素。先把[1,10^5]中的每个数的质数分数(不同质因子的数目)预处理出来,记作数组PRIMES。然后用单调栈求出每个i左侧质数分数大于等于PRIMES[nums[i]]的最近的数的下标left[i(不存在则为-1),以及右侧质数分数大于PRIMES[nums[i]]的最近的数的下标right[i](不存在则为n)。注意,不能在i左侧包含质数分数和PRIMES[nums[i]]一样的数,否则不满足题目「如果多个元素质数分数相同且最高,选择下标最小的一个」的要求。所以对于左侧用"大于等于"。那么子数组的左端点可以在(left[i],i)内,子数组的右端点可以在[i,rght[i])内。根据乘法原理,一共有tot=(i-left[i])×(right[i]-i)个子数组以nums[i]作为这个子数组的质数分数。设k'=min(k,tot),则nums[i对答案的贡献为nums[i]^k'(用快速幂计算)。根据上式,按照nums从大到小的顺序计算贡献,一边计算一边更新剩余操作次数k。