biweekly contest 159。

題目

https://leetcode.com/problems/count-prime-gap-balanced-subarrays/description/

解法

相似題 3578. count partitions with max min difference at most k
如果忽略質數至少 2 個限制的話,概念幾乎相同。


首先篩質數。方便起見,把非質數的 nums[i] 改成 0。以下討論到的元素都是質數。

對於子陣列問題,常見技巧是枚舉右、維護左
枚舉右端點,維護左端點最遠到哪。

子陣列長度越大,極值差只增不減
可用 sorted list 維護子陣列的元素,滑動窗口維護最大合法子陣列。若極值差超過 k 則縮減左端點。
右端點 = i,最遠左端點 = j 時,[j..i] 都是極值差不超過 k 的左端點,有 i-j+1 個子陣列。


但題目還要求子陣列至少兩個元素

同樣道理,另外維護變數 j2,表示至多一個質數的最遠左端點。
一個質數的情況下,極值差等於 0,也滿足不超過 k 的條件,有 j <= j2。
[j2..i] 質數都不夠,扣除 i-j2+1 個子陣列。

兩項整理:

i-j+1 - (i-j2+1)
j2-j

時間複雜度 O(N log N)。
空間複雜度 O(N)。

from sortedcontainers import SortedList as SL

MX = 10 ** 5 + 5
sieve = [True] * (MX + 1)
sieve[0] = sieve[1] = False
for i in range(2, int(MX ** 0.5) + 1):
    if sieve[i]:
        for j in range(i * i, MX + 1, i):
            sieve[j] = False


class Solution:
    def primeSubarray(self, nums: List[int], k: int) -> int:
        for i, x in enumerate(nums):
            if not sieve[x]:
                nums[i] = 0

        ans = 0
        j1 = 0  # leftbound for k-diff
        sl = SL()
        j2 = 0  # to delete: at most 1 prime
        cnt = 0
        for i, x in enumerate(nums):
            if x > 0:
                cnt += 1
                sl.add(x)

                # maintain k-diff
                while sl[-1] - sl[0] > k:
                    if nums[j1] > 0:
                        sl.remove(nums[j1])
                    j1 += 1

                # maintain at most 1 prime
                while cnt > 1:
                    if nums[j2] > 0:
                        cnt -= 1
                    j2 += 1

            # # add k-diff
            # ans += i-j1+1
            # # delete at most 1 prime
            # ans -= i-j2+1
            ans += j2-j1

        return ans