結果

問題 No.515 典型LCP
ユーザー Min_25Min_25
提出日時 2017-05-06 11:33:14
言語 C++14
(gcc 13.2.0 + boost 1.83.0)
結果
AC  
実行時間 428 ms / 1,000 ms
コード長 5,690 bytes
コンパイル時間 3,580 ms
コンパイル使用メモリ 100,848 KB
実行使用メモリ 77,056 KB
最終ジャッジ日時 2023-10-12 14:59:50
合計ジャッジ時間 5,421 ms
ジャッジサーバーID
(参考情報)
judge15 / judge14
このコードへのチャレンジ(β)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 428 ms
76,896 KB
testcase_01 AC 274 ms
76,444 KB
testcase_02 AC 170 ms
76,652 KB
testcase_03 AC 4 ms
13,760 KB
testcase_04 AC 4 ms
13,696 KB
testcase_05 AC 190 ms
77,032 KB
testcase_06 AC 188 ms
77,056 KB
testcase_07 AC 181 ms
77,028 KB
testcase_08 AC 207 ms
76,856 KB
testcase_09 AC 128 ms
76,440 KB
testcase_10 AC 125 ms
76,300 KB
testcase_11 AC 129 ms
76,372 KB
testcase_12 AC 129 ms
76,296 KB
testcase_13 AC 127 ms
76,432 KB
testcase_14 AC 67 ms
76,332 KB
testcase_15 AC 175 ms
77,008 KB
testcase_16 AC 173 ms
76,844 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <cstdio>
#include <cassert>
#include <cmath>
#include <cstring>

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <functional>
#include <stack>
#include <queue>

#include <tuple>

#define getchar getchar_unlocked
#define putchar putchar_unlocked

#define _rep(_1, _2, _3, _4, name, ...) name
#define rep2(i, n) rep3(i, 0, n)
#define rep3(i, a, b) rep4(i, a, b, 1)
#define rep4(i, a, b, c) for (int i = int(a); i < int(b); i += int(c))
#define rep(...) _rep(__VA_ARGS__, rep4, rep3, rep2, _)(__VA_ARGS__)

using namespace std;

using i64 = long long;
using u32 = unsigned;
using u64 = unsigned long long;
using f80 = long double;

template <typename CharType>
struct InducedSort {
  using chr_t = CharType;
  using check_t = bool;

  int operator [] (int i) const {
    return sa[i];
  }

  static inline bool is_lms(const vector<check_t>& is_s, int i) {
    return is_s[i] && !is_s[i - 1];
  }

  InducedSort(const chr_t* str, int n, const int char_count=128) : str(str), size(n), sa(n, -1) {
    if (n <= 1) { sa[0] = 0; return; }
    if (n == 2) { sa[0] = 1; sa[1] = 0; return; }
    const auto is_s = scan_types();
    const auto offsets = calc_offsets(char_count);
    put_lms(is_s, offsets);
    scan_forward(is_s, offsets);
    scan_backward(is_s, offsets);
    calc_lms_pos(is_s, offsets);
    scan_forward(is_s, offsets);
    scan_backward(is_s, offsets);
  }

  void calc_lms_pos(const vector<check_t>& is_s, vector<int> offsets) {
    int next_size, next_char_count;
    tie(next_size, next_char_count) = convert(is_s);
    if (next_char_count < next_size) {
      auto res = InducedSort<int>(sa.data() + size - next_size, next_size, next_char_count);
      copy(res.sa.begin(), res.sa.end(), sa.begin());
    } else {
      rep(i, next_size) sa[sa[size - next_size + i]] = i;
    }
    int j = size - next_size;
    rep(i, 1, size) if (is_lms(is_s, i)) sa[j++] = i;
    rep(i, next_size) sa[i] = sa[size - next_size + sa[i]];
    rep(i, next_size, size) sa[i] = -1;
    for (int i = next_size - 1; i >= 0; --i) {
      int j = sa[i]; sa[i] = -1;
      sa[--offsets[str[j] + 1]] = j;
    }
  }

  pair<int, int> convert(const vector<check_t>& is_s) {
    int lms_count = 0;
    rep(i, size) if (sa[i] > 0 && !is_s[sa[i] - 1] && is_s[sa[i]]) sa[lms_count++] = sa[i];
    rep(i, lms_count, size) sa[i] = -1;
    int char_count = 0;
    sa[lms_count + (sa[0] >> 1)] = char_count++;
    rep(i, 1, lms_count) {
      int prev = sa[i - 1], curr = sa[i];
      for (int ofs = 0; ; ++ofs) {
        if (str[curr + ofs] != str[prev + ofs] || is_s[curr + ofs] != is_s[prev + ofs]) {
          char_count++; break;
        } else if (ofs > 0 && (is_lms(is_s, curr + ofs) || is_lms(is_s, prev + ofs))) {
          break;
        }
      }
      sa[lms_count + (curr >> 1)] = char_count - 1;
    }
    for (int i = size - 1, tail = i; i >= lms_count; --i) if (sa[i] >= 0) sa[tail--] = sa[i];
    return {lms_count, char_count};
  }
  void scan_forward(const vector<check_t>& is_s, vector<int> offsets) {
    rep(i, size) if (sa[i] >= 1 && !is_s[sa[i] - 1]) sa[offsets[str[sa[i] - 1]]++] = sa[i] - 1;
  }
  void scan_backward(const vector<check_t>& is_s, vector<int> offsets) {
    for (int i = size - 1; i >= 0; --i) if (sa[i] >= 1 && is_s[sa[i] - 1]) sa[--offsets[str[sa[i] - 1] + 1]] = sa[i] - 1;
  }
  void put_lms(const vector<check_t>& is_s, vector<int> offsets) {
    rep(i, 1, size) if (is_lms(is_s, i)) sa[--offsets[str[i] + 1]] = i;
  }
  vector<int> calc_offsets(int char_count) {
    vector<int> ret(char_count + 1, 0);
    rep(i, size) ret[int(str[i]) + 1] += 1;
    rep(i, 1, char_count + 1) ret[i] += ret[i - 1];
    return ret;
  }
  vector<check_t> scan_types() {
    vector<check_t> is_s(size);
    is_s.back() = 1;
    for (int i = size - 2; i >= 0; --i) is_s[i] = (str[i] < str[i + 1]) || (str[i] == str[i + 1] && is_s[i + 1]);
    return is_s;
  }
  pair< vector<int>, vector<int> > calc_lcp() {
    vector<int> lcp(size);
    vector<int> rank(size);
    rep(i, size) rank[sa[i]] = i;
    int k = 0;
    rep(i, size - 1) {
      int j = sa[rank[i] - 1];
      if (k) --k;
      while (i + k < size && j + k < size && str[i + k] == str[j + k]) ++k;
      lcp[rank[i] - 1] = k;
    }
    return {lcp, rank};
  }
  const chr_t* str;
  int size;
  vector<int> sa;
};

void solve() {
  int N;
  while (~scanf("%d", &N)) {
    static char buff[1000010];
    static int offsets[100010];
    static int tab[20][800010];

    int ofs = 0;
    rep(i, N) {
      scanf("%s", buff + ofs);
      offsets[i] = ofs;
      ofs += strlen(buff + ofs);
    }
    offsets[N] = ofs;
    buff[ofs++] = '\0';
    auto sa = InducedSort<char>(buff, ofs);
    auto p = sa.calc_lcp();
    auto& lcp = p.first, &rank = p.second;

    int size = lcp.size(), k = __lg(size);
    rep(i, size) tab[0][i] = lcp[i];
    rep(t, 1, k + 1) {
      int l = 1 << (t - 1);
      rep(i, 0, size - 2 * l + 1) tab[t][i] = min(tab[t - 1][i], tab[t - 1][i + l]);
    }

    int M; i64 x, d; scanf("%d %lld %lld", &M, &x, &d);
    const i64 N2 = i64(N) * (N - 1);

    i64 ans = 0;
    rep(_, M) {
      int i = x / (N - 1), j = x % (N - 1);
      if (i > j) swap(i, j);
      else ++j;
      int len = min(offsets[i + 1] - offsets[i], offsets[j + 1] - offsets[j]);
      int p1 = rank[offsets[i]], p2 = rank[offsets[j]];
      if (p2 < p1) swap(p1, p2);
      int l = __lg(p2 - p1);
      ans += min(len, min(tab[l][p1], tab[l][p2 - (1 << l)]));
      if ((x += d) >= N2) x -= N2;
    }
    printf("%lld\n", ans);
  }
}

int main() {
  auto beg = clock();
  solve();
  auto end = clock();
  fprintf(stderr, "%.3f sec\n", double(end - beg) / CLOCKS_PER_SEC);
}
0