Official

H - Duplicate Editorial by en_translator


First of all, if \(S\) has adjacent 2-or-greater digits, then the answer is -1.
We consider the other cases. For example, let \(S=\) 1121131. S transitions by the operations as follows:

  • 1121131
  • 111211113
  • 11112111111
  • 11111211111
  • 111111211111
    \(\vdots\)

We can observe the following property from the sequences:

  • The suffix consisting of the same digits (like 3 and 111111 above) is shortened one by one, and eventually vanishes.
  • The occurrences of digits between 2 and 9 that is not in such a suffix do not decrease.
  • Consecutive occurrences of 1s that is not in such a suffix increases by \((x-1)\) in each step, where \(x\) is the preceding digit. For example, the occurrences of leading 11 increases by \(2-1=1\) in each step.

The point of this rule is that consecutive occurrences of the same digits decrease its length only when it is a suffix. Thus, the answer can be found by storing \(S\) in run-length encoding, and simulating the lengths of \(S\) and the number of operations while popping the tail of run-length-compressed sequence. (For more details, please refer to the sample code.)
The complexity is \(\mathrm{O}(N)\), which is fast enough.

  • Sample code (C++)
#include <bits/stdc++.h>
using namespace std;

#include "atcoder/modint.hpp"
using mint = atcoder::modint998244353;

vector<pair<char, int>> RunLengthEncoding(string& S) {
  if (S.empty()) return {};
  vector<pair<char, int>> ret;
  char c = S[0];
  int n = 1;
  for (int i = 1; i < (int)S.size(); i++) {
    if (S[i] == c)
      n++;
    else {
      ret.emplace_back(c, n);
      c = S[i], n = 1;
    }
  }
  ret.emplace_back(c, n);
  return ret;
}

int main() {
  int N;
  string S;
  cin >> N >> S;
  for (int i = 0; i + 1 < N; i++) {
    if (S[i] >= '2' and S[i + 1] >= '2') {
      cout << "-1\n";
      exit(0);
    }
  }
  auto rle = RunLengthEncoding(S);
  mint t = 0;
  char last = '1';
  while (!rle.empty()) {
    char c;
    mint n;
    tie(c, n) = rle.back();
    rle.pop_back();
    if (c == '1') {
      n += t * (last - '1');
      t += n;
    } else {
      t += 1;
    }
    last = c;
  }
  cout << (t - 1).val() << "\n";
}

posted:
last update: