結果
問題 | No.515 典型LCP |
ユーザー | furuya1223 |
提出日時 | 2019-10-13 12:16:38 |
言語 | C++14 (gcc 12.3.0 + boost 1.83.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 17,325 bytes |
コンパイル時間 | 1,960 ms |
コンパイル使用メモリ | 141,964 KB |
実行使用メモリ | 32,796 KB |
最終ジャッジ日時 | 2024-05-08 12:30:08 |
合計ジャッジ時間 | 15,148 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | TLE | - |
testcase_01 | TLE | - |
testcase_02 | WA | - |
testcase_03 | AC | 2 ms
5,376 KB |
testcase_04 | AC | 2 ms
5,376 KB |
testcase_05 | WA | - |
testcase_06 | WA | - |
testcase_07 | WA | - |
testcase_08 | WA | - |
testcase_09 | WA | - |
testcase_10 | WA | - |
testcase_11 | WA | - |
testcase_12 | WA | - |
testcase_13 | WA | - |
testcase_14 | WA | - |
testcase_15 | WA | - |
testcase_16 | WA | - |
ソースコード
#include <algorithm> #include <bitset> #include <cassert> #include <chrono> #include <cmath> #include <complex> #include <cstdint> #include <fstream> #include <functional> #include <iomanip> #include <iostream> #include <limits> #include <list> #include <map> #include <queue> #include <random> #include <regex> #include <set> #include <sstream> #include <stack> #include <string> #include <sys/timeb.h> #include <vector> using namespace std; #define repr(i, a, b) for (int i = (int)(a); i < (int)(b); i++) #define rep(i, n) repr(i, 0, n) #define reprrev(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--) #define reprev(i, n) reprrev(i, 0, n) #define repi(itr, ds) for (auto itr = ds.begin(); itr != ds.end(); itr++) #define chmin(mi, val) mi = min(mi, val) #define chmax(ma, val) ma = max(ma, val) #define all(a) (a).begin(), (a).end() #define rall(a) (a).rbegin(), (a).rend() #define mp make_pair #define mt make_tuple #define INF 1050000000 #define INFR INT_MAX #define INFL (long long)(4e18) #define INFLR LLONG_MAX #define EPS (1e-10) //#define MOD 1000000007 #define MOD 998244353 #define PI 3.141592653589793238 #define RMAX 4294967295 using vi = vector<int>; using vvi = vector<vector<int>>; using vvvi = vector<vector<vector<int>>>; using vvvvi = vector<vector<vector<vector<int>>>>; using ll = long long; using vll = vector<ll>; using vvll = vector<vector<ll>>; using vvvll = vector<vector<vector<ll>>>; using vd = vector<double>; using vvd = vector<vector<double>>; using vb = vector<bool>; using vvb = vector<vector<bool>>; using vc = vector<char>; using vvc = vector<vector<char>>; using vs = vector<string>; using vvs = vector<vector<string>>; using Pi = pair<int, int>; using vPi = vector<Pi>; using vvPi = vector<vector<Pi>>; using vvvPi = vector<vector<vector<Pi>>>; using vvvvPi = vector<vector<vector<vector<Pi>>>>; using Pll = pair<ll, ll>; using vPll = vector<Pll>; using Pd = pair<double, double>; using vPd = vector<Pd>; template <class T> using vec = vector<T>; template <class T> using pql = priority_queue<T, vector<T>, greater<T>>; using Comp = complex<double>; // vvvvvvvvvvvvvvvvvvvvvvv debug output vvvvvvvvvvvvvvvvvvvvvvv // vector input template <typename T> istream &operator>>(istream &is, vector<T> &vec) { for (T &x : vec) is >> x; return is; } // pair template <typename T, typename U> ostream &operator<<(ostream &os, const pair<T, U> &pair_var) { os << "(" << pair_var.first << ", " << pair_var.second << ")"; return os; } // vector template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) { os << "{"; for (int i = 0; i < vec.size(); i++) { os << vec[i] << (i + 1 == vec.size() ? "" : ", "); } os << "}"; return os; } // deque template <typename T> ostream &operator<<(ostream &os, const deque<T> &vec) { os << "{"; for (int i = 0; i < vec.size(); i++) { os << vec[i] << (i + 1 == vec.size() ? "" : ", "); } os << "}"; return os; } // map template <typename T, typename U> ostream &operator<<(ostream &os, const map<T, U> &map_var) { os << "{"; repi(itr, map_var) { os << *itr; itr++; if (itr != map_var.end()) os << ", "; itr--; } os << "}"; return os; } // set template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) { os << "{"; repi(itr, set_var) { os << *itr; itr++; if (itr != set_var.end()) os << ", "; itr--; } os << "}"; return os; } // multiset template <typename T> ostream &operator<<(ostream &os, const multiset<T> &set_var) { os << "{"; repi(itr, set_var) { os << *itr; itr++; if (itr != set_var.end()) os << ", "; itr--; } os << "}"; return os; } #define DUMPOUT cerr void dump_func() { DUMPOUT << endl; } template <class Head, class... Tail> void dump_func(Head &&head, Tail &&... tail) { DUMPOUT << head; if (sizeof...(Tail) > 0) { DUMPOUT << ", "; } dump_func(std::move(tail)...); } #ifdef DEBUG_ #define DEB #define dump(...) \ DUMPOUT << " " << string(#__VA_ARGS__) << ": " \ << "[" << to_string(__LINE__) << ":" << __FUNCTION__ << "]" \ << endl \ << " ", \ dump_func(__VA_ARGS__) #else #define DEB if (false) #define dump(...) #endif // ^^^^^^^^^^^^^^^^^^^^^^^ debug output ^^^^^^^^^^^^^^^^^^^^^^^ string YN(bool y, int id = 0) { if (id) cout << id; return (y ? "YES" : "NO"); } string yn(bool y, int id = 0) { if (id) cout << id; return (y ? "Yes" : "No"); } string ON(bool y, int id = 0) { if (id) cout << id; return (y ? "OK" : "NG"); } int dir4[4][2] = {{0, -1}, {-1, 0}, {1, 0}, {0, 1}}; int dir8[8][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}}; char dirchar[4] = {'<', '^', '>', 'v'}; // [a,b) int irand(int a, int b) { static mt19937 Rand(static_cast<unsigned int>(time(nullptr))); uniform_int_distribution<int> dist(a, b - 1); return dist(Rand); } // [a,b) double drand(int a, int b) { static mt19937 Rand(static_cast<unsigned int>(time(nullptr))); uniform_real_distribution<double> dist(a, b); return dist(Rand); } // https://qiita.com/IgnorantCoder/items/3101d6276e9bdddf872c template <typename A, typename F> inline auto transform(const A &v, F &&f) { using result_type = decltype(std::declval<F>()(std::declval<typename A::value_type>())); vector<result_type> y(v.size()); std::transform(std::cbegin(v), std::cend(v), std::begin(y), f); return y; } // generate vector which has multiple dimension template <class T> vector<T> make_v(size_t size, const T &init) { return vector<T>(size, init); } template <class... Ts> auto make_v(size_t size, Ts... rest) { return vector<decltype(make_v(rest...))>(size, make_v(rest...)); } template <typename T> T Max(vector<T> a) { return *max_element(all(a)); } template <typename T> T Min(vector<T> a) { return *min_element(all(a)); } template <typename T> T Sum(vector<T> a) { return accumulate(all(a), (T)0); } // for counting using map template <typename T> void Add(map<T, int> &m, T item) { if (m.find(item) == m.end()) { m[item] = 1; } else { m[item]++; } } // for counting using map template <typename T> void Erase(map<T, int> &m, T item) { if (m.find(item) == m.end()) { } else { if (m[item] == 1) { m.erase(item); } else { m[item]--; } } } // get method for map with default value template <typename T, typename U> U Get(map<T, U> m, T key, U def) { if (m.find(key) == m.end()) { return def; } else { return m[key]; } } template <typename T> inline bool Contains(const set<T> &t, const T &key) { return t.find(key) != t.end(); } template <typename T, typename U> inline bool Contains(const map<T, U> &t, const T &key) { return t.find(key) != t.end(); } template <class T> struct Edge { int from, to; T cost; bool operator<(Edge e) { return cost < e.cost; } Edge(int f, int t, T c) : from(f), to(t), cost(c) {} }; template <class T> ostream &operator<<(ostream &os, Edge<T> &edge) { os << "(" << edge.from << "->" << edge.to << ":" << edge.cost << ")"; return os; } template <class T = int> class Graph { int n; bool directed; vector<vector<Edge<T>>> edges; public: Graph(int n, bool directed) : n(n), directed(directed), edges(vector<vector<Edge<T>>>(n)) {} void add_edge(int s, int t, T cost) { edges[s].emplace_back(s, t, cost); if (!directed) { edges[t].emplace_back(t, s, cost); } } Graph() {} vector<Edge<T>> &operator[](size_t i) { return edges[i]; } int size() const { return n; } }; //====================================================== template <class T> class SegTree { int n; // 葉の数 vector<T> data; // データを格納するvector T def; // 初期値かつ単位元 function<T(T, T)> operation; // 区間クエリで使う処理 function<T(T, T)> update; // 点更新で使う処理 // 区間[a,b)の総和。ノードk=[l,r)に着目している。 T _query(int a, int b, int k, int l, int r) { if (r <= a || b <= l) return def; // 交差しない if (a <= l && r <= b) return data[k]; // a,l,r,bの順で完全に含まれる else { T c1 = _query(a, b, 2 * k + 1, l, (l + r) / 2); // 左の子 T c2 = _query(a, b, 2 * k + 2, (l + r) / 2, r); // 右の子 return operation(c1, c2); } } public: // _n:必要サイズ, _def:初期値かつ単位元, _operation:クエリ関数, // _update:更新関数 SegTree(size_t _n, T _def, function<T(T, T)> _operation, function<T(T, T)> _update) : def(_def), operation(_operation), update(_update) { n = 1; while (n < _n) { n *= 2; } data = vector<T>(2 * n - 1, def); } // 場所i(0-indexed)の値をxで更新 void change(int i, T x) { i += n - 1; data[i] = update(data[i], x); while (i > 0) { i = (i - 1) / 2; data[i] = operation(data[i * 2 + 1], data[i * 2 + 2]); } } // [a, b)の区間クエリを実行 T query(int a, int b) { return _query(a, b, 0, 0, n); } // 添字でアクセス T operator[](int i) { return data[i + n - 1]; } }; class SuffixArray { static const int L_type = 0, S_type = 1, LMS_type = 2; static void induce_sort(const vector<int> &v, vector<int> &sa, const vector<int> &type, vector<int> start, vector<int> end) { int len = sa.size(); // L-type の要素を各バケットに前から詰める for (int i = 0; i < len; i++) { if (sa[i] == -1) continue; if (sa[i] - 1 >= 0 && type[sa[i] - 1] == L_type) { sa[start[v[sa[i] - 1]]++] = sa[i] - 1; } if (i != 0 && type[sa[i]] == LMS_type) { sa[i] = -1; } } // S-type の要素を各バケットに後ろから詰める for (int i = len - 1; i >= 0; i--) { if (sa[i] == -1) continue; if (sa[i] - 1 >= 0 && type[sa[i] - 1] != L_type) { sa[--end[v[sa[i] - 1]]] = sa[i] - 1; } } } public: vector<int> str; // 入力配列 vector<int> suffix_array; vector<int> order; // SA における添字: order[suffix_array[i]] = i vector<int> lpc; // SA[i], SA[i+1] の LPC 長 SuffixArray(vector<int> &v, int char_num) { str = v; suffix_array = SA_IS(str, char_num); } SuffixArray(const string &s) { str.resize(s.size()); for (int i = 0; i < s.size(); i++) { str[i] = s[i] - 'a' + 1; } suffix_array = SA_IS(str, 26); } static vector<int> SA_IS(vector<int> &v, int char_num) { if (v.size() == 1) { // 再帰の終わり return vector<int>(1, 0); } v.push_back(0); char_num++; int len = v.size(); vector<int> tmp_sa(len, -1); vector<int> type(len); vector<int> start(char_num), end(char_num); // バケットiの注目範囲 vector<int> LMS; // LMS の開始位置 vector<int> LMS_order(len, -1); // LMS のソート順序(非 LMS では -1) // type の判定 type.back() = S_type; end[0] = 1; for (int i = len - 2; i >= 0; i--) { if (v[i] > v[i + 1]) { type[i] = L_type; if (type[i + 1] == S_type) { LMS.push_back(i + 1); type[i + 1] = LMS_type; LMS_order[i + 1] = 0; } } else if (v[i] < v[i + 1]) { type[i] = S_type; } else { type[i] = type[i + 1]; } end[v[i]]++; } // start, end の計算 start[0] = 0; for (int i = 1; i < char_num; i++) { end[i] += end[i - 1]; start[i] = end[i - 1]; } // Induce Sort の準備 for (int i = 0; i < len; i++) { if (LMS_order[i] != -1) { tmp_sa[--end[v[i]]] = i; } } // end の復元 for (int i = 0; i < char_num - 1; i++) { end[i] = start[i + 1]; } end[char_num - 1] = len; // Induce Sort で LMS-substring をソートする induce_sort(v, tmp_sa, type, start, end); // LMS のみからなる数列を作成する // LMS のソート順序を調べる int counter = 0; int prev_lms = -1; // 1 つ前の LMS の先頭 for (int i = 0; i < len; i++) { if (LMS_order[tmp_sa[i]] != -1) { LMS_order[tmp_sa[i]] = ++counter; if (prev_lms == -1) { prev_lms = tmp_sa[i]; continue; } // 1 つ前の LMS と同じか判定 bool different = false; for (int j = 0; j < len; j++) { // j 文字目(prev_lms+j と tmp_sa[i]+j)をチェック if (prev_lms + j >= len || tmp_sa[i] + j >= len || (j != 0 && (LMS_order[prev_lms + j] != -1 || LMS_order[tmp_sa[i] + j] != -1))) { break; } if (v[prev_lms + j] != v[tmp_sa[i] + j]) { different = true; break; } } if (!different) { LMS_order[tmp_sa[i]] = --counter; } prev_lms = tmp_sa[i]; } } vector<int> new_v; // v での出現順に LMS-substring の順位が並ぶ vector<int> position(len, 0); // 各 LMS の開始位置 counter = 0; for (int i = 0; i < len; i++) { if (LMS_order[i] != -1) { new_v.push_back(LMS_order[i]); position[counter++] = i; } } // SA-IS を再帰適用して LMS をソートする vector<int> lms_sa = SA_IS(new_v, new_v.size()); // Induce Sort の準備 fill(tmp_sa.begin(), tmp_sa.end(), -1); for (int i = lms_sa.size() - 1; i >= 0; i--) { if (LMS_order[position[lms_sa[i]]] != -1) { tmp_sa[--end[v[position[lms_sa[i]]]]] = position[lms_sa[i]]; } } // end の復元 for (int i = 0; i < char_num - 1; i++) { end[i] = start[i + 1]; } end[char_num - 1] = len; // Induce Sort で saffix array を完成させる induce_sort(v, tmp_sa, type, start, end); tmp_sa.erase(tmp_sa.begin()); // 先頭の空文字列を削除 v.pop_back(); // 末尾に足した 0 を削除 return tmp_sa; } void calc_lpc() { if (lpc.size() != 0) return; int len = str.size(); lpc.resize(len); order.resize(len); for (int i = 0; i < len; i++) { order[suffix_array[i]] = i; } int h = 0; for (int i = 0; i < len; i++) { // str[i..] と SA でその前にある接尾辞の LPC を求める if (order[i] == 0) { h = 0; continue; } int j = suffix_array[order[i] - 1]; if (h > 0) h--; while (i + h < len && j + h < len) { if (str[i + h] != str[j + h]) break; h++; } lpc[order[i] - 1] = h; } } }; int main() { ll N; cin >> N; string S; vi start(N); rep(i, N) { start[i] = S.size(); string s; cin >> s; S += s; } dump(S); dump(start); ll M, x, d; cin >> M >> x >> d; SuffixArray SA(S); dump(SA.suffix_array); SA.calc_lpc(); dump(SA.lpc); SegTree<int> st(SA.lpc.size(), INF, [](int a, int b) { return min(a, b); }, [](int a, int b) { return b; }); rep(i, SA.lpc.size()) { st.change(i, SA.lpc[i]); } ll ans = 0; rep(k, M) { int i = (x / (N - 1)) + 1; int j = (x % (N - 1)) + 1; if (i > j) swap(i, j); else j++; x = (x + d) % (N * (N - 1)); i--, j--; dump(i, j, start[i], start[j], SA.order[start[i]], SA.order[start[j]]); ans += st.query(SA.order[start[i]], SA.order[start[j]]); } cout << ans << endl; return 0; }