0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【競技プログラミング】AtCoder Beginner Contest 248_D問題

Posted at

問題

要約

長さNの数列A = (A1, ..., AN)が与えられる。

その後、Q個のクエリに答える必要があります。各クエリは以下の形式で与えられる

  • 整数L, R, Xが与えられる。

  • 数列AのL番目からR番目までの要素(AL, ..., AR)の中で、値がXに等しい要素の個数を求める。

    • N: 数列Aの長さ
    • A: 与えられる数列 (A1, ..., AN)
    • Q: クエリの数
    • L: 各クエリでの範囲の開始位置
    • R: 各クエリでの範囲の終了位置
    • X: 各クエリで探す値

既存投稿一覧ページへのリンク

一覧ページ

アプローチ

累積和と二分探索を組み合わせてクエリを処理する

解法手順

  1. 入力を受け取る:

    • 数列の長さNを読み込む
    • 数列Aの要素を読み込む
  2. 累積和の準備:

    • 各値の出現位置を記録する配列acmを作成する
    • 数列Aを走査し、各要素の出現位置をacmに記録する
  3. クエリ処理:

    • クエリの数Qを読み込む
    • 各クエリに対して以下の処理を行う:
      a. L, R, Xを読み込む
      b. Xの出現位置リストlstを取得する
      c. 二分探索を使用して、L以上の最小のインデックスlを求める
      d. 二分探索を使用して、R以下の最大のインデックスrを求める
      e. r - lを計算し、結果を出力する
  4. 全てのクエリに対して3の処理を繰り返す

ACコード

ac.py
from bisect import bisect_left, bisect  # 二分探索のためのモジュールをインポート

def io_func():
    # 入力を受け取る関数
    N = int(input())  # 数列の長さを読み込む
    A = list(map(int, input().split()))  # 数列Aの要素を読み込む
    Q = int(input())  # クエリの数を読み込む
    queries = [list(map(int, input().split())) for _ in range(Q)]  # クエリを読み込む
    return N, A, queries

def solve(N, A, queries):
    # メインの処理を行う関数
    acm = [[] for _ in range(N+1)]  # 各値の出現位置を記録する配列を初期化
    
    # 数列Aを走査し、各要素の出現位置をacmに記録
    for i, a in enumerate(A, 1):
        acm[a].append(i)
    
    # 各クエリに対して処理を行う
    for L, R, X in queries:
        lst = acm[X]  # Xの出現位置リストを取得
        l = bisect_left(lst, L)  # L以上の最小のインデックスを二分探索で求める
        r = bisect(lst, R)  # R以下の最大のインデックスを二分探索で求める
        print(r - l)  # 結果を出力

if __name__=="__main__":
    # メイン処理
    N, A, queries = io_func()  # 入力を受け取る
    solve(N, A, queries)  # 解を求める

###
# N: 数列の長さ
# A: 入力された数列
# queries: クエリのリスト
# acm: 各値の出現位置を記録する配列
# L, R, X: 各クエリの左端、右端、探索する値
# lst: 特定の値Xの出現位置リスト
# l, r: 二分探索で求めた範囲内のインデックス

# 1. 入力処理(io_func関数):
#    - 数列の長さ、数列の要素、クエリの数とその内容を読み込む
# 2. メイン処理(solve関数):
#    a. 累積和の準備:
#       - 各値の出現位置を記録する配列acmを作成
#    b. クエリ処理:
#       - 各クエリに対して、指定された値Xの出現回数を二分探索で効率的に計算
#       - 結果を出力
# 3. メイン処理の呼び出し:
#    - io_func関数で入力を受け取り、solve関数で解を求める

トレース

入力例

N = 11
A = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
queries = [(3,7,1)]
trace.py
    # メインの処理を行う関数
    acm = [[] for _ in range(N+1)]  # 各値の出現位置を記録する配列を初期化
# [[], [], [], [], [], [], [], [], [], [], [], []]

    # 数列Aを走査し、各要素の出現位置をacmに記録
    for i, a in enumerate(A, 1):
        acm[a].append(i)
# [[], [2, 4], [7], [1, 10], [3], [5, 9, 11], [8], [], [], [6], [], []]

    # 各クエリに対して処理を行う
    for L, R, X in queries:
# L=3, R=7, X=1    
        lst = acm[X]  # Xの出現位置リストを取得
# [2, 4]
        l = bisect_left(lst, L)  # L以上の最小のインデックスを二分探索で求める
# l = bisect_left([2, 4], 3) = 1
        r = bisect(lst, R)  # R以下の最大のインデックスを二分探索で求める
# r = bisect_left([2, 4], 7) = 2
        print(r - l)  # 結果を出力
# 1
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?