配点: 300 点 / 実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 230 / NoviSteps: 3Q
問題概要
長さ の整数列
があり、最初
である。以下のクエリを全部で
個処理せよ。
1 p x:を
に変更する。
2 p:を出力する。
3 k:全体を
回左巡回シフトする。
制約
- 入力は全て整数
- 全てのクエリは以下の制約を満たす。
考察
各クエリを愚直に行おうとすると、クエリ3に の計算量がかかってしまい、
個のクエリを処理する中で TLE する。
そこで、実際に の各要素をシフトさせる代わりに、シフトが行われた回数を記録しておくことにする。
現時点でシフトが行われた回数を とするとき、
の
番目の要素は実際には
番目の位置にあることになる。ただし、これは 0-indexed である。
したがって、クエリ3が呼ばれるごとに に
を加えることで、このクエリは
の計算量で処理することができる。
クエリ1, 2はそのまま で処理できるので、全体としては
で解くことができた。
実装例
#include <bits/stdc++.h> using namespace std; #define all(x) (x).begin(), (x).end() #define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++) using ll = long long; // ======================================== // int main() { int N, Q; cin >> N >> Q; vector<int> A(N); iota(all(A), 1); ll left_shift = 0; while (Q--) { int t; cin >> t; if (t == 1) { int p, x; cin >> p >> x; p--; A[(p + left_shift) % N] = x; } else if (t == 2) { int p; cin >> p; p--; cout << A[(p + left_shift) % N] << endl; } else if (t == 3) { int k; cin >> k; left_shift += k; } } return 0; }
実装時間: 10分
コメント
「配列全体に何かの操作をする場合は offset を取っておく」というのは、クエリ処理系の問題では典型である。