公式

B - ロボットの宝集め / Robot's Treasure Collection 解説 by MMNMM 印刷ページ


制約から、一回の操作 2 を \(O(Q)\) 時間で(十分高速に)シミュレーションできれば、全体で \(O(SQ)\) 時間となり実行時間制限に間に合いそうです。

ロボットの移動をシミュレーションするのはそのまま実装しても \(O(Q)\) 時間になります。 「現在いる部屋に宝があるか(すでに回収されていないか)」を判定する部分は少し工夫をする必要があります。 例えば以下のような工夫をすることで、シミュレーション全体を \(O(Q)\) 時間や \(O(Q\log Q)\) 時間とすることができます。

  • 現在のシミュレーションで宝を回収した部屋の一覧を平衡二分探索木やハッシュテーブルを使って管理する
  • それぞれの部屋に宝があるかと、現在のシミュレーションで宝を回収した部屋の一覧を配列で管理し、シミュレーションが完了したら今回のシミュレーションで回収した部屋だけに宝を戻す
  • それぞれの部屋について、最後に宝を回収したのが何回目の操作によるシミュレーションかを管理する

実装例は以下のようになります。

#include <iostream>
#include <vector>
#include <set>
using namespace std;

int main() {
    int N, Q, M;
    cin >> N >> Q >> M;
    vector<int> A(N);
    for (int& a : A) {
        cin >> a;
    }
    string S;
    cin >> S;

    for (int i = 0; i < M; ++i) {
        int type;
        cin >> type;
        if (type == 1) { // 書き換え操作は
            int p;
            char c;
            cin >> p >> c;
            S[p - 1] = c; // そのまま書き換える
        } else { // スコアはシミュレーションで求める
            set<int> collected_index; // 今回のシミュレーションで回収した宝の一覧
            int now_index = 0; // 現在の部屋
            long ans = 0; // 現在の獲得スコア
            for (char c : S) {
                if (c == 'L') {
                    now_index = max(0, now_index - 1);
                }
                if (c == 'R') {
                    now_index = min(N - 1, now_index + 1);
                }
                if (c == 'P') {
                    // まだその部屋から回収していなければ
                    if (!collected_index.contains(now_index)) {
                        ans += A[now_index]; // スコアを獲得
                    }
                    collected_index.emplace(now_index);
                }
                if (c == 'B') {
                    now_index = 0;
                }
            }
            cout << ans << endl;
        }
    }
    return 0;
}
N, Q, M = map(int, input().split())
A = list(map(int, input().split()))
S = list(input())

for i in range(M):
    type, *arg = input().split()
    if int(type) == 1: # 書き換え操作は
        p, c = arg
        S[int(p) - 1] = c # そのまま書き換える
    else: # スコアはシミュレーションで求める
        collected_index = set() # 今回のシミュレーションで回収した宝の一覧
        now_index = 0 # 現在の部屋
        ans = 0 # 現在の獲得スコア
        for c in S:
            if c == 'L':
                now_index = max(0, now_index - 1)
            if c == 'R':
                now_index = min(N - 1, now_index + 1)
            if c == 'P':
                # まだその部屋から回収していなければ
                if not now_index in collected_index:
                    ans += A[now_index] # スコアを獲得
                collected_index.add(now_index)
            if c == 'B':
                now_index = 0
        print(ans)

投稿日時:
最終更新: