典型90【010 – Score Sum Queries(★2)】をpython解説

Python

AtCoder の問題を解くために必要な実力を付けるために作られた「典型問題」を解いていく企画として、「典型90」があります。

今回は、その内、の10問目である「010 – Score Sum Queries(★2)」を解説していきたいと思います。

問題名 【010 – Score Sum Queries(★2)】

010 – Score Sum Queries(★2)

考察

結論から先にいうと今回は、累積和を用いる問題です。

問題は

学籍番号が1~Nの連番で決められていて、そのN人が2つのクラス(AクラスとBクラスとします)に割り振られている。
※(1組の1番の人と2組の1番の人が同時に存在しない)
任意の区間で、A組の人の合計とB組の人の合計点数を出力しなさい

という問題です。

制約が、N == Q <= 10**5なので、Q回の操作で、N人の人のクラスと点数を毎回計算するとTLEしてしまいます

Question ではどうするか?

事前に0からi番目までの合計点数を計算しておく

事前に累積された値を計算しておくことで、
LからRまでの区間 = 0~R の合計点数 – 0~(L-1)の合計点数 
で求めることができます。

このように、0からi番目の累積された数字を持つ典型解法を累積和といいます。

事前に累積和を計算しておくことで、任意の区間の合計点数を出力するのは、O(1)で行うことができますので、Q人の回のクエリにおいて実行しても間に合います。

典型解法:事前に累積和

コード

import sys
def LI(): return list(map(int,sys.stdin.readline().rstrip().split()))
def II(): return int(sys.stdin.readline())
def MI(): return map(int,sys.stdin.readline().rstrip().split())
def S(): return sys.stdin.readline().rstrip()
readline = sys.stdin.readline
sys.setrecursionlimit(10 ** 6)

N = II()
class_A = [0 for i in range(N)]
class_B = [0 for i in range(N)]

for i in range(N):
    c,p = MI()
    if c == 1:
        class_A[i]=p
    else:
        class_B[i]=p

Q = II()
ruiseki_A = [0]
ruiseki_B = [0]

for i in range(N):
    ruiseki_A.append(ruiseki_A[-1]+class_A[i])
    ruiseki_B.append(ruiseki_B[-1]+class_B[i])

# print(ruiseki_A)
# print(ruiseki_B)
for q in range(Q):
    l,r = MI()
    l -= 1
    
    ans_A = ruiseki_A[r]-ruiseki_A[l]
    ans_B = ruiseki_B[r]-ruiseki_B[l]
    print(ans_A,ans_B)

まとめ

累積和の問題は、計算量が1操作あたりの計算量がO(1)になることが多くて、なんかよい

前の問題【008 – AtCounter(★4)】

次の問題

コメント

タイトルとURLをコピーしました