D - 蛍光ペンでマーキング / Highlighting with a Fluorescent Pen 解説 by admin
Gemini 3.0 FlashOverview
Given a sequence of \(N\) characters, when an interval of length \(W\) is marked \(K\) times, the problem asks to determine how many times each character is ultimately marked.
Discussion
Naive Approach and Its Limitations
The simplest method is to loop through each marking instruction (from \(L_i\) to \(L_i + W - 1\)) and increment the count one by one. However, this method requires up to \(N\) addition operations per marking. Since marking is performed \(K\) times, the overall time complexity is \(O(NK)\). Looking at the constraints, \(N, K \le 2 \times 10^5\), so \(NK \approx 4 \times 10^{10}\), which will not finish within the time limit (generally, about \(10^8\) operations can be processed per second).
Efficient Solution
To efficiently perform the operation of “adding a value to a specific interval all at once,” we use an algorithm called the “imos method” (difference array technique). Using the imos method, a single range addition can be done with just 2 array operations (\(O(1)\)), and by scanning through the entire array once at the end (\(O(N)\)), we can determine the value at each position.
Algorithm
Steps of the Imos Method
- Prepare a difference array:
Prepare an array
diffof size \(N+2\) and initialize all elements to 0. - Record the markings:
Let the start position of each marking be \(L\) and the end position be \(R = L + W - 1\).
- Add \(1\) to
diff[L](indicating that a marking starts here) - Subtract \(1\) from
diff[R + 1](indicating that the effect of the marking ends here)
- Add \(1\) to
- Compute the prefix sum:
Take the prefix sum of the array
difffrom the beginning. The number of times the \(j\)-th character is marked is given by \(\sum_{i=1}^{j} diff[i]\).
Concrete Example
For \(N=5, W=3, K=1\) with \(L_1=2\):
- The marking range is from the 2nd character to the \(2+3-1=4\)th character.
- diff[2] += 1
- diff[4 + 1] -= 1
- State of the diff array: [0, 0, 1, 0, 0, -1]
- Taking the prefix sum: 0, 0, 1, 1, 1, 0
- Count for each character: 0 1 1 1 0, which is correctly computed.
Complexity
- Time complexity: \(O(N + K)\)
- Recording the \(K\) markings takes \(O(K)\), and the final prefix sum computation takes \(O(N)\). This is sufficiently fast under the given constraints.
- Space complexity: \(O(N)\)
- An array of roughly length \(N\) is needed for storing differences and for output.
Implementation Notes
Fast I/O: In Python, when \(N\) or \(K\) is large, repeatedly calling
input()orprint()can become an I/O bottleneck. You can speed things up by reading all input at once withsys.stdin.read().split()or by usingsys.stdout.write().Array size: Since we access the index \(R+1\) (i.e., \(L+W\)), the array size should be slightly larger than \(N+1\) (e.g., \(N+2\)) to prevent out-of-bounds errors.
Source Code
import sys
def main():
# 高速な入出力のために、すべての入力を一度に読み込んで空白で分割します。
# N: 文字の総数, W: 蛍光ペンの幅, K: マーキングの回数
data = sys.stdin.read().split()
if not data:
return
# 最初の3つの要素が N, W, K です。
n = int(data[0])
w = int(data[1])
k = int(data[2])
# いもす法(累積和の応用)のための差分配列を用意します。
# 1-indexed で管理するため、サイズを N + 2 とします。
# diff[i] は i 文字目のマーキング回数の変化量を表します。
diff = [0] * (n + 2)
# 各マーキングの開始位置 L_i は data[3] 以降に格納されています。
# マーキングされる範囲は [L_i, L_i + W - 1] です。
for i in range(3, 3 + k):
l = int(data[i])
# 範囲の開始位置でカウントを増やします。
diff[l] += 1
# 範囲の終了位置の直後(L_i + W)でカウントを減らします。
# 制約 L_i <= N - W + 1 により、L_i + W は最大で N + 1 となります。
if l + w <= n + 1:
diff[l + w] -= 1
# 差分配列の累積和を計算して、各文字が何回マーキングされたかを求めます。
results = [0] * n
current_count = 0
for j in range(1, n + 1):
current_count += diff[j]
results[j - 1] = current_count
# 結果をスペース区切りの文字列として結合し、一括で出力します。
sys.stdout.write(" ".join(map(str, results)) + "\n")
if __name__ == "__main__":
main()
This editorial was generated by gemini-3-flash-preview.
投稿日時:
最終更新: