1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| #include <bits/stdc++.h>
using u64 = uint64_t;
const int kMaxN = 1e5 + 5, kMaxL = 1e6 + 5, kMod = 1e9 + 7;
int n; int len[kMaxL], sum[kMaxL]; u64 pw[kMaxL]; std::string s[kMaxN]; std::vector<int> id[kMaxN], f[kMaxN]; std::vector<u64> hs[kMaxN];
inline int add(int x, int y) { return (x + y >= kMod ? x + y - kMod : x + y); } inline int sub(int x, int y) { return (x >= y ? x - y : x - y + kMod); } inline void inc(int &x, int y) { (x += y) >= kMod ? x -= kMod : x; } inline void dec(int &x, int y) { (x -= y) < 0 ? x += kMod : x; }
void prework() { pw[0] = 1; for (int i = 1; i <= 1e6; ++i) pw[i] = 13331ull * pw[i - 1]; for (int i = 1; i <= n; ++i) { hs[i].resize(len[i] + 1); for (int j = 1; j <= len[i]; ++j) hs[i][j] = 13331ull * hs[i][j - 1] + s[i][j]; } }
int getpos(int x, int p) { if (x < p) return x; else return x + 1; }
u64 gethash(std::vector<u64> &hs, int l, int r) { return hs[r] - hs[l - 1] * pw[r - l + 1]; }
u64 gethash(std::vector<u64> &hs, int l, int r, int p) { if (p < l || p > r) return gethash(hs, l, r); else return gethash(hs, l, p - 1) * pw[r - p] + gethash(hs, p + 1, r); }
bool cmp(int a1, int b1, int a2, int b2) { int L = 0, R = std::min(len[a1] - 1, len[a2] - 1) + 1, res = 0; while (L + 1 < R) { int mid = (L + R) >> 1; if (gethash(hs[a1], 1, getpos(mid, b1), b1) == gethash(hs[a2], 1, getpos(mid, b2), b2)) L = res = mid; else R = mid; } if (res == std::min(len[a1] - 1, len[a2] - 1)) { if (res == len[a1] - 1) return 1; else return s[a1][getpos(res + 1, b1)] == '.'; } else { return s[a1][getpos(res + 1, b1)] <= s[a2][getpos(res + 1, b2)]; } }
void dickdreamer() { std::cin >> n; for (int i = 1; i <= n; ++i) { std::cin >> s[i]; s[i] = " " + s[i] + "."; len[i] = (int)s[i].size() - 1; } prework(); for (int i = 1; i <= n; ++i) { id[i].resize(len[i] + 1); int l = 1, r = len[i], lst = 0; for (int j = 1; j <= len[i] - 1; ++j) { if (s[i][j] < s[i][j + 1]) { for (int k = j; k >= lst + 1; --k) id[i][r--] = k; lst = j; } else if (s[i][j] > s[i][j + 1]) { for (int k = lst + 1; k <= j; ++k) id[i][l++] = k; lst = j; } } for (int j = lst + 1; j <= len[i]; ++j) id[i][l++] = j; } f[1].resize(len[1] + 1); for (int i = 1; i <= len[1]; ++i) f[1][i] = 1; for (int i = 2; i <= n; ++i) { f[i].resize(len[i] + 1); for (int j = 1; j <= len[i - 1]; ++j) sum[j] = add(sum[j - 1], f[i - 1][j]); int p = 0; for (int j = 1; j <= len[i]; ++j) { for (; p < len[i - 1] && cmp(i - 1, id[i - 1][p + 1], i, id[i][j]); ++p) {} f[i][j] = sum[p]; } } int ans = 0; for (int i = 1; i <= len[n]; ++i) inc(ans, f[n][i]); std::cout << ans << '\n'; }
int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; while (T--) dickdreamer(); return 0; }
|