#include #include #include using namespace std; using namespace atcoder; #pragma GCC target("avx2") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") using M1 = modint1000000007; using M2 = modint998244353; using hash_t = pair; namespace atcoder { bool operator<(const M1 &t1, const M1 &t2) { return t1.val() < t2.val(); } bool operator<(const M2 &t1, const M2 &t2) { return t1.val() < t2.val(); } } // namespace atcoder struct Hash { int n; string s; long long B; bool calc_rev; fenwick_tree bit1, bit1_rev; fenwick_tree bit2, bit2_rev; vector Bp1, Bp1_inv; vector Bp2, Bp2_inv; Hash() {} Hash(string &s, bool calc_rev = true) : s(s), n(s.length()), calc_rev(calc_rev), Bp1(n + 1), Bp2(n + 1) { Bp1_inv.resize(n + 1), Bp2_inv.resize(n + 1); random_device seed; mt19937 engine(seed()); B = (long long)(engine()) + 1000; bit1 = fenwick_tree(n); bit2 = fenwick_tree(n); M1 p1 = 1; M2 p2 = 1; Bp1[0] = Bp1_inv[0] = 1, Bp2[0] = Bp2_inv[0] = 1; for (int i = 0; i < n; i++) { bit1.add(i, p1 * s[i]); bit2.add(i, p2 * s[i]); p1 *= B, p2 *= B; Bp1[i + 1] = p1; Bp2[i + 1] = p2; Bp1_inv[i + 1] = p1.inv(); Bp2_inv[i + 1] = p2.inv(); } if (not calc_rev) return; bit1_rev = fenwick_tree(n); bit2_rev = fenwick_tree(n); for (int i = 0; i < n; i++) { bit1_rev.add(i, Bp1[n - i - 1] * s[i]); bit2_rev.add(i, Bp2[n - i - 1] * s[i]); } } void update(int i, char c) { bit1.add(i, Bp1[i] * c - bit1.sum(i, i + 1)); bit2.add(i, Bp2[i] * c - bit2.sum(i, i + 1)); if (not calc_rev) return; bit1_rev.add(i, Bp1[n - i - 1] * c - bit1_rev.sum(i, i + 1)); bit2_rev.add(i, Bp2[n - i - 1] * c - bit2_rev.sum(i, i + 1)); } hash_t query(int l, int r, bool rev = false) { assert(l <= r); if (rev) { assert(calc_rev); hash_t res = {bit1_rev.sum(l, r), bit2_rev.sum(l, r)}; res.first *= Bp1_inv[n - r]; res.second *= Bp2_inv[n - r]; return res; } hash_t res = {bit1.sum(l, r), bit2.sum(l, r)}; res.first *= Bp1_inv[l]; res.second *= Bp2_inv[l]; return res; } bool is_palindrome(int l, int r) { assert(calc_rev); return query(l, (l + r) / 2, false) == query((l + r + 1) / 2, r, true); } }; int main() { string s; cin >> s; int n = s.length(); Hash hash(s, false); using mint = M1; vector dp(n); vector used(n); auto f = [&](auto self, int l, int r) -> mint { if (used[l]) return dp[l]; mint res = 1; for (int l2 = l + 1, r2 = r - 1; l2 <= r2; l2++, r2--) { if (hash.query(l, l2) == hash.query(r2, r)) { res += self(self, l2, r2); } } used[l] = true; return dp[l] = res; }; cout << f(f, 0, n).val() << "\n"; }