#include #include #include #include #include #include #include #include #include #include #include #include #include #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 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& 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& is_s, vector 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(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 convert(const vector& 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& is_s, vector 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& is_s, vector 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& is_s, vector offsets) { rep(i, 1, size) if (is_lms(is_s, i)) sa[--offsets[str[i] + 1]] = i; } vector calc_offsets(int char_count) { vector 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 scan_types() { vector 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, vector > calc_lcp() { vector lcp(size); vector 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 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(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); }