【AtCoder】ABC 465 C - Reverse Permutation

C - Reverse Permutationatcoder.jp favicon

実行時間制限: 2 sec / メモリ制限: 1024 MiB / Difficulty: 443 / NoviSteps: 2Q / 配点: 300 点

問題概要

整数 NNoxからなる長さ NN の文字列 SS が与えられる。 長さ NN の整数列 A=(1,2,,N)A=(1,2,\ldots,N) に対して、 k=1,2,,Nk=1,2,\ldots,N の順に以下の操作を行う:

  • Sk=S_k=oである場合、AA の先頭 kk 項を反転する。
  • Sk=S_k=x である場合、何もしない。

全ての操作を終えた後の AA を求めよ。

制約

  • 2N5×1052\le N\le 5\times 10^5

考察

操作毎に配列 AA を反転させていると TLE になってしまうので、まずは操作を言い換えよう。

  • はじめ、 A=()A = () とする。
  • k=1,2,,Nk = 1, 2, \ldots, N の順に以下の操作を行う。
    • AA の末尾に kk を追加する。
    • Sk=S_k=oである場合、AA を反転する。

さらに、あらかじめ反転されたかどうかのフラグを持っておくと、以下のように操作を言い換えることができる。

  • Si=S_i =o の場合、フラグを反転させる。その後、フラグがtrueなら AA の先頭に、falseなら末尾に ii を追加する。
  • Si=S_i =x の場合、フラグがtrueなら AA の末尾に、falseなら先頭に ii を追加する。

最後に、フラグがtrueなら配列を反転させて出力する。

これは、サンプルケースを見ると、何となくエスパーできるかもしれない。


実装についてだが、 AA の先頭と末尾に要素を追加する必要があるので、dequeを使うとよいだろう。

実装例

CPP
1.#include <bits/stdc++.h>
2.using namespace std;
3.
4.#define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++)
5.
6.// ======================================== //
7.
8.int main()
9.{
10. int N;
11. string S;
12. cin >> N >> S;
13.
14. deque<int> que;
15. bool reversed = false;
16. rep(k, 0, N) {
17. if (S[k] == 'o') {
18. reversed = !reversed;
19. if (reversed) {
20. que.push_back(k);
21. }
22. else {
23. que.push_front(k);
24. }
25. }
26. else {
27. if (reversed) {
28. que.push_front(k);
29. }
30. else {
31. que.push_back(k);
32. }
33. }
34. }
35.
36. if (reversed) {
37. while (!que.empty()) {
38. cout << que.back() + 1 << " ";
39. que.pop_back();
40. }
41. }
42. else {
43. while (!que.empty()) {
44. cout << que.front() + 1 << " ";
45. que.pop_front();
46. }
47. }
48. cout << endl;
49.
50. return 0;
51.}
atcoder.jp favicon

実装時間: 10分

コメント

操作の言い換えがちょっと難しい。