首先注意到題目中的第 i 位外星人將在 i 年後成年,因此成年的順序即為給定的陣列順序 1,2,⋯,N。接著,將 i 從 j 收到石頭視為 j 給出石頭給 i,其中 j<i。如此便能在 i 成年時計算其收到的石頭數量,並依此計算給出的石頭數量。
轉換後便可以從維護收到的石頭數量下手,對於第 i 位外星人,若其能夠給出 g 個石頭,則編號為 [i+1,i+g] 的外星人,其收到石頭數量增加 1,這種區間加操作可以用 差分陣列(Difference Arrays) 維護。
對差分陣列做前綴和即可得到 i 從前面的人那裡收到的石頭數量 cur。而根據原本的石頭數量 Ai 和 cur,以及後面的人數量 N−i,可以算出給出的石頭數量 g,最終第 i 位外星人的石頭數量為 Ai+cur−g。
複雜度分析
時間複雜度:O(N)
空間複雜度:O(N)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
N = int(input()) A = list(map(int, input().split()))
d = [0] * (N + 1) ans = [0] * N cur = 0# 收到的石頭數量,對差分陣列做前綴和得到 for i, x inenumerate(A): cur += d[i] give = min(x + cur, N - 1 - i) # 給出的石頭數量,這裡為 0-based if give > 0: # 區間 [i + 1, i + give] 的石頭數量增加 1 d[min(i + 1, N)] += 1 d[min(i + give + 1, N)] -= 1 ans[i] = x + cur - give print(*ans)
有 N 個年糕,第 i 個年糕的大小為 Ai,其中 (1≤i≤N),並且 Ai 已經按照大小以升序排列。
製作一個鏡餅(疊加的年糕)需要將兩個年糕疊放在一起,且上面年糕的大小不超過下面年糕的一半。具體來說,給定兩個年糕 A 和 B,其大小分別為 a 和 b,當且僅當 a≤2b 時,可以通過將年糕 A 放在年糕 B 上來製作一個鏡餅。
現在你需要計算可以同時製作多少個鏡餅。
更精確地說,找出最大的非負整數 K,使得以下條件成立:
從 N 個年糕中選出 2K 個,形成 K 對。對於每一對,將其中一個年糕疊在另一個上,製作 K 個鏡餅。
約束條件
2≤N≤5×105
1≤Ai≤109(1≤i≤N)
Ai≤Ai+1(1≤i<N)
思路:貪心(Greedy) + 二分搜尋(Binary Search)
基於貪心原則,為了盡可能組成 k 對,則上面的 k 個年糕應盡可能的小,也就是說,在上面的 k 個年糕最好是最小的 k 個。
方法一:O(NlogN)
而若存在 k 對,則最小的 k 個年糕和區間內其他 k 個年糕存在有效的配對,此時將某個年糕與尚未使用且更大的年糕交換,必也能配對成功。換句話說,若存在 k 對,則區間內最小的 k 個年糕和最大 k 個年糕必存在有效的配對。因此,判斷是否存在 k 對,只需要檢查這 2k 個年糕是否能配對成功即可,故檢查函數 check() 的時間複雜度為 O(k)。
在得到檢查函數後,由於 check() 函數有越小越合法的單調性,因此可以對 k 進行二分搜尋,由於最大的配對數量為 ⌊2N⌋,因此需要搜尋 O(logN) 次。
複雜度分析
時間複雜度:O(NlogN)。總共進行二分搜尋 O(logN) 次,每次檢查需要 O(k) 時間,其中 k 為配對數量,可以視為 O(N)。
空間複雜度:O(N)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
N = int(input()) A = list(map(int, input().split()))
# 是否可以組成 k 對年糕 defcheck(k): for i inrange(k): if A[i] * 2 > A[N - k + i]: returnFalse returnTrue
# 二分搜尋 left, right = 0, N // 2 while left <= right: mid = (left + right) // 2 if check(mid): left = mid + 1 else: right = mid - 1 print(right) # 越小越合法,求最大的合法值
方法二: O(N)
這個思路可以用在 G 題,以下用 [L,R] 表示搜尋區間,本題中只需考慮 L=1,R=N 的情況。
若區間 [L,R] 內可以組成 K 對,則最小的 K 個數和最大的 K 個數必能配對成功,其中最小的 K 個數為 [L,L+K−1],最大的 K 個數為 [R−K+1,R]。
但若最小的 K 個數中有一個數無法配對成功,則會影響到後續的數,使後續的數需要 往後遞移 ,因此其實只考慮最小的 K 個數的右端點 L+K−1 、以及 [L,L+K−1] 中的最大間距 max_gap 即可。
如果 L+K−1+max_gap>R,則說明往後遞移之後會超過範圍,也就是說 K 太大了,需要縮小。
N, M, A, B = map(int, input().split()) intervals = [tuple(map(int, input().split())) for _ inrange(M)]
classMatrix: def__init__(self, mat): self.mat = mat
def__mul__(self, other): p, q, r = len(self.mat), len(other.mat), len(other.mat[0]) res = [[0] * r for _ inrange(p)] for k inrange(q): for i inrange(p): for j inrange(r): res[i][j] |= self.mat[i][k] & other.mat[k][j] return Matrix(res) def__getitem__(self, key): i, j = key return self.mat[i][j] def__setitem__(self, key, value): i, j = key self.mat[i][j] = value MG = Matrix([[0] * B for _ inrange(B)]) # Good for i inrange(A - 1, B): MG[0, i] = 1 for i inrange(1, B): MG[i, i - 1] = 1
MB = Matrix([[0] * B for _ inrange(B)]) # Bad for i inrange(1, B): MB[i, i - 1] = 1
defpow(x, k, pow_mat): res = x for i inrange(41): if k & (1 << i): res = pow_mat[i] * res return res
cur = 1 m = [[0] for _ inrange(B)] m[0] = [1] x = Matrix(m) for (L, R) in intervals: # (cur, L-1] is good x = pow(x, L - 1 - cur, pow_MG) # (L-1, R] is bad x = pow(x, R - L + 1, pow_MB) cur = R
# (cur, N] is good x = pow(x, N - cur, pow_MG) print("Yes"if x[0, 0] else"No")
1girl, solo, long hair, looking at viewer, blush, smile, bangs, blue eyes, skirt, shirt, hair ornament, long sleeves, bow, ribbon, closed mouth, blue hair, standing, jacket, hair ribbon, white shirt, ponytail, flower, white hair, sidelocks, outdoors, open clothes, sky, alternate costume, hair flower, blunt bangs, mole, open jacket, tree, plaid, petals, mole under eye, night, feet out of frame, plaid skirt, white jacket, cherry blossoms, building, night sky, pink flower, puffy long sleeves, lantern, railing, architecture, east asian architecture, falling petals,
Anime style, female character in traditional Japanese outfit, standing on a wooden balcony, surrounded by cherry blossoms, night sky with stars, traditional Japanese buildings, romantic and serene atmosphere.
賽時只有寫了 A 到 E 題,看到通過人數決定先去寫 G 題,但沒想出來就直接去休息了。賽後看完 F 題才發現這道題我是有可能寫出來的題目,賽時不應該沒看就直接放棄的。