#include using namespace std; #define SZ(x) (int) (x).size() #define REP(i, n) for(int i = 0; i < (n); i++) #define FOR(i, a, b) for(int i = (a); i < (b); i++) #define REPR(i, n) for(int i = (n) -1; i >= 0; i--) #define ALL(s) (s).begin(), (s).end() #define so(V) sort(ALL(V)) #define rev(V) reverse(ALL(V)) #define uni(v) v.erase(unique(ALL(v)), (v).end()) typedef long long unsigned int llu; //typedef long long ll; typedef vector vi; //typedef vector vll; typedef vector vb; typedef vector vvi; const double EPS = 1e-9; const int MOD = 1e9 + 7; const int INF = (1 << 29); //const ll LINF = 1e18; const double PI = acos(-1); template vector make_v(size_t a) { return vector(a); } template auto make_v(size_t a, Ts... ts) { return vector(ts...))>( a, make_v(ts...)); } template typename enable_if::value == 0>::type fill_v( T& t, const V& v) { t = v; } template typename enable_if::value != 0>::type fill_v( T& t, const V& v) { for(auto& e: t) fill_v(e, v); } template bool chmax(T& a, const T& b) { if(a < b) { a = b; return true; } return false; } template bool chmin(T& a, const T& b) { if(a > b) { a = b; return true; } return false; } template istream& operator>>(istream& is, pair& p) { cin >> p.first >> p.second; return is; } template istream& operator>>(istream& is, vector& vec) { for(T& x: vec) is >> x; return is; } template ostream& operator<<(ostream& os, vector& vec) { REP(i, SZ(vec)) { if(i != 0) os << " "; os << vec[i]; } return os; } #include using namespace atcoder; struct RollingHash { static const uint64_t mod = (1ull << 61ull) - 1; using uint128_t = __uint128_t; uint64_t base1, base2; vector pow1, pow2; RollingHash() { mt19937_64 mt(chrono::steady_clock::now() .time_since_epoch() .count()); uniform_int_distribution rand( 1e9, RollingHash::mod - 1); base1 = rand(mt); base2 = rand(mt); pow1.push_back(1); pow2.push_back(1); } // 必要分のpow配列を追加で求める。 inline void expand(int sz) { int pre_sz = SZ(pow1); if(pre_sz < sz + 1) { for(int i = pre_sz - 1; i < sz; i++) { pow1.push_back(mul(pow1[i], base1)); pow2.push_back(mul(pow2[i], base2)); } } } pair, vector> build( const string& s) { expand(SZ(s) + 1); vector hash1 = vector(SZ(s) + 1); vector hash2 = vector(SZ(s) + 1); REP(i, SZ(s)) { hash1[i + 1] = add(mul(hash1[i], base1), s[i]); hash2[i + 1] = add(mul(hash2[i], base2), s[i]); } return { hash1, hash2 }; } template pair, vector> build( const vector& s) { expand(SZ(s) + 1); vector hash1 = vector(SZ(s) + 1); vector hash2 = vector(SZ(s) + 1); REP(i, SZ(s)) { hash1[i + 1] = add(mul(hash1[i], base1), s[i]); hash2[i + 1] = add(mul(hash2[i], base2), s[i]); } return { hash1, hash2 }; } pair query( const pair, vector>& hash, int begin, int length) { assert(begin + length <= SZ(hash.first)); assert(begin >= 0); assert(length > 0); expand(length); return { add(hash.first[begin + length], mod - mul(hash.first[begin], pow1[length])), add(hash.second[begin + length], mod - mul(hash.second[begin], pow2[length])) }; } static inline uint64_t add(uint64_t a, uint64_t b) { if((a += b) >= mod) a -= mod; return a; } static inline uint64_t mul(uint64_t a, uint64_t b) { uint128_t c = (uint128_t) a * b; return add(c >> 61, c & mod); } }; using mint = modint1000000007; int main() { cin.tie(nullptr); ios::sync_with_stdio(false); string S; cin >> S; int N = SZ(S); RollingHash rh; auto hash = rh.build(S); auto dp = make_v(N + 1); dp[0] = 1; mint ans(0); FOR(lr, 1, N + 1) { REP(ll, lr) { int rr = N - ll; int rl = N - lr; if(ll == rl && lr == rr) { ans += dp[ll]; } if(lr > rl) continue; int len = lr - ll; if(rh.query(hash, ll, len) != rh.query(hash, rl, len)) continue; dp[lr] += dp[ll]; if(lr == rl) { ans += dp[ll]; } } } cout << ans.val() << endl; return 0; }