Submission #3369820


Source Code Expand

#include <bits/stdc++.h>
#define ll long long
#define REP(i, n) for (ll (i) = 0; (i) < (n); (i)++)
#define REPI(i, a, b) for (ll (i) = (a); (i) < (b); (i)++)
#define int long long
using namespace std;
using II = pair<int, int>;
using VI = vector<int>;
using VVI = vector<VI>;
using VVVI = vector<VVI>;
using VII = vector<II>;

class SuffixArray {
  void set_lcp() {
    lcp = VI(N - 1);
    int h = 0;
    REP (i, N) {
      if (h > 0) h--;
      if (rank[i] == N - 1) continue;
      int j = sorted[rank[i] + 1]; // 比べる対象(辞書順が一つ大きいもの)
      for (; i + h < N && j + h < N; h++) {
        if (S[i + h] != S[j + h]) break;
      }
      lcp[rank[i]] = h;
    }
  }
public:
  int N;
  string S;
  VI rank; // rank[i]: iから始まるsuffixの辞書順での順位
  VI sorted; // sorted[i]: suffixが辞書順i番目となる開始位置のindex
  VI lcp; // lcp[i]: S[sorted[i]...]とS[sorted[i + 1]...]が先頭何文字一致しているか
  SuffixArray(string s) {
    S = s;
    N = S.size();
    sorted = VI(N); rank = VI(N);
    REP (i, N) {
      sorted[i] = i;
      rank[i] = S[i];
    }

    int k;
    function<bool(int, int)> compare_sa = [this, &k](int i, int j) {
      if (rank[i] != rank[j]) { return rank[i] < rank[j]; }
      int ri = i + k < N ? rank[i + k] : -1;
      int rj = j + k < N ? rank[j + k] : -1;
      return ri < rj;
    };

    for (k = 1; k < N; k *= 2) {
      sort(sorted.begin(), sorted.end(), compare_sa);
      VI tmp(N, 0);
      REPI (i, 1, N) {
        tmp[sorted[i]] = tmp[sorted[i - 1]] + compare_sa(sorted[i - 1], sorted[i]);
      }
      rank = tmp;
    }
    set_lcp();
  }

  // sizeがTと等しく初めてT以上になるようなSの部分文字列(sortedのイテレータを返す)
  VI::iterator lower_bound(string T) {
    int l = -1, r = N;
    while (r - l > 1) {
      int mid = (l + r) / 2;
      if (S.compare(sorted[mid], T.size(), T) < 0) {
        l = mid;
      } else {
        r = mid;
      }
    }
    return sorted.begin() + r;
  }

  // sizeがTと等しく初めてTより大きくなるようなSの部分文字列(sortedのイテレータを返す)
  VI::iterator upper_bound(string T) {
    int l = -1, r = N;
    while (r - l > 1) {
      int mid = (l + r) / 2;
      if (S.compare(sorted[mid], T.size(), T) <= 0) {
        l = mid;
      } else {
        r = mid;
      }
    }
    return sorted.begin() + r;
  }

  // S2が部分文字列として何回出現するか
  int count(string S2) {
    return upper_bound(S2) - lower_bound(S2);
  }
};

signed main() {
  string S; cin >> S;
  SuffixArray sa(S);
  int N = S.size();
  int ans = N * (N + 1) * (N + 2) / 6;
  REP (i, N - 1) {
    ans -= sa.lcp[i] * (sa.lcp[i] + 1) / 2;
  }
  cout << ans << endl;
}

Submission Info

Submission Time
Task E - 部分文字列
User knshnb
Language C++14 (GCC 5.4.1)
Score 100
Code Size 2872 Byte
Status AC
Exec Time 206 ms
Memory 2816 KB

Judge Result

Set Name Sample Subtask1 Subtask2 Subtask3
Score / Max Score 0 / 0 15 / 15 35 / 35 50 / 50
Status
AC × 3
AC × 12
AC × 14
AC × 17
Set Name Test Cases
Sample sample_1.txt, sample_2.txt, sample_3.txt
Subtask1 sample_1.txt, sample_2.txt, sample_3.txt, sub1_1.txt, sub1_2.txt, sub1_3.txt, sub1_4.txt, sub1_5.txt, sub1_6.txt, sub1_7.txt, sub1_8.txt, sub1_9.txt
Subtask2 sample_1.txt, sample_2.txt, sample_3.txt, sub1_1.txt, sub1_2.txt, sub1_3.txt, sub1_4.txt, sub1_5.txt, sub1_6.txt, sub1_7.txt, sub1_8.txt, sub1_9.txt, sub2_1.txt, sub2_2.txt
Subtask3 sample_1.txt, sample_2.txt, sample_3.txt, sub1_1.txt, sub1_2.txt, sub1_3.txt, sub1_4.txt, sub1_5.txt, sub1_6.txt, sub1_7.txt, sub1_8.txt, sub1_9.txt, sub2_1.txt, sub2_2.txt, sub3_1.txt, sub3_2.txt, sub3_3.txt
Case Name Status Exec Time Memory
sample_1.txt AC 1 ms 256 KB
sample_2.txt AC 1 ms 256 KB
sample_3.txt AC 1 ms 256 KB
sub1_1.txt AC 1 ms 256 KB
sub1_2.txt AC 1 ms 256 KB
sub1_3.txt AC 1 ms 256 KB
sub1_4.txt AC 1 ms 256 KB
sub1_5.txt AC 1 ms 256 KB
sub1_6.txt AC 1 ms 256 KB
sub1_7.txt AC 1 ms 256 KB
sub1_8.txt AC 1 ms 256 KB
sub1_9.txt AC 1 ms 256 KB
sub2_1.txt AC 2 ms 256 KB
sub2_2.txt AC 3 ms 256 KB
sub3_1.txt AC 7 ms 384 KB
sub3_2.txt AC 31 ms 768 KB
sub3_3.txt AC 206 ms 2816 KB