Problem:
G: 回文部分列 (Palindromic Subsequences)
問題
英小文字のみからなる文字列
S
が与えられるので、この文字列
S
の
連続とは限らない
部分列であって、回文であるものは何種類あるかを求めてください。
ここで、
S
の連続とは限らない部分列とは、元の文字列
S
から
1
文字以上
|S|
文字以下を任意に選択し (選択するそれぞれの文字の位置は非連続でも良い)、それらを元の順番通りに連結させてできた文字列のことを指します。この問題において、空文字列は部分列として認められないことに注意してください。
また、文字列
X
が回文であるとは、元の文字列
X
と、
X
を反転した文字列
X’
が等しいことを指します。
さらに、異なる部分列のとりかたの結果
同じ回文が生成されたとしても、それは重複して数えない
ことに注意してください。例えば
S =
acpc
である場合、
2
文字目のみからなる部分列と、
4
文字目のみからなる部分列はどちらも回文
c
ですが、これは複数回数えず、合わせて一度だけ数えることとします。
答えは非常に大きくなることがあるので、
1,000,000,007
で割った余りを出力してください。
入力形式
S
制約
1 \leq |S| \leq 2,000
S
に含まれる文字は英小文字のみである
出力形式
答えを
1,000,000,007
で割った余りを
1
行で出力してください。
入力例1
acpc
出力例1
5
文字列
acpc
の連続とは限らない部分列であって回文であるものは、
a
,
c
,
cc
,
cpc
,
p
の
5
種類です。部分列の種類数を数えることに注意してください。
入力例2
z
出力例2
1
条件を満たす部分列は
z
のみです。空文字列は部分列として認められないことに注意してください。
入力例3
madokamagica
出力例3
28

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
// #include<atcoder/all>
using namespace std;
// using namespace atcoder;

using ll=long long;
using ld=long double;
using pl=pair<ll,ll>;
using vpl=vector<pl>;
using vl=vector<ll>;
using vvl=vector<vl>;

long double pi=atan2(0,-1);

#define rep(i,n) for(long long i=0LL;i<n;i++)
#define rrep(i,a,b) for(long long i=a;i>=b;i--)
#define REP1(i,k,n) for(long long i=k;i<n;i++)
#define REP2(i,k,n,d) for(long long i=k;i<n;i+=d)
#define overload4(a, b, c, d, e, ...) e
#define FOR(...) overload4(__VA_ARGS__, REP2,REP1)(__VA_ARGS__)
#define ALL(v) v.begin(),v.end()
template<typename T>ostream&operator<<(ostream& os,vector<T>&v){for(int i = 0;i < int(size(v));i++)os << v[i] << (i+1==int(size(v))?"":" ");return os;}
template<typename T>istream&operator>>(istream& is,vector<T>&v){for(auto &in : v)is >> in;return is;}
ll INF = 1152921504606846976;
/* INF = 1LL << 60 */


// //using mint = ld;
// //using mint = modint998244353;ll MOD = 998244353;
// using mint = modint1000000007;ll MOD = 1000000007;
// //using mint = modint;

// using vm = vector<mint>;
// using vvm = vector<vm>;

// ostream&operator<<(ostream& os,vector<mint>&v){for(int i = 0;i < int(size(v));i++)os << v[i].val() << (i+1==int(size(v))?"":" ");return os;}


vl dx = {1,0,-1,0}, dy = {0,1,0,-1};
//----------------------------------------------


int main(){
  ios::sync_with_stdio(false);cin.tie(nullptr);cout<<fixed<<setprecision(15);
//==============================================
  ll M = 1000000007;

  string S;
  cin>>S;
  string T = S;
  reverse(ALL(T));
  ll N = S.size();

  vvl ns(N+1,vl(26,N));
  vvl nt(N+1,vl(26,N));

  auto f = [](string S,vvl &next){
    rrep(i,S.size()-1,0){
      rep(j,26){
        next[i][j] = next[i+1][j];
      }
      next[i][S[i]-'a'] = i;
    }
  };

  f(S,ns);
  f(T,nt);

  vvl dp(N+9,vl(N+9));
  dp[0][0] = 1;

  rep(i,N) rep(j,N){
    rep(c,26){
      dp[ns[i][c]+1][nt[j][c]+1] += dp[i][j];
      dp[ns[i][c]+1][nt[j][c]+1] %= M;
    }
  }

  ll ans =0;
  rep(i,N+1) rep(j,N+1) if(i+j<=N){
    ll kind = 0;
    rep(c,26) if(ns[i][c] < N-j) kind++;
    ans += (kind+1)*dp[i][j]%M;
    ans %= M;
  }
  ans-=1;
  ans = (ans+M*100)%M;
  cout << ans<< endl;



}
accuracy: 1
time_ms: 410
memory_kb: 35788
final_rank: 15

code_snippet: //#define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
using namespace std;
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif

// --- マクロ定義 ---
#define rrep(i, a, b) for (int i = (a); i < (b); ++i)
#define rep(i, n) rrep(i,0,n)
#define bfor(bit,a,b) for(int bit = (a); bit < (1<<(b)); ++bit)
#define brep(bit,n) bfor(bit,0,n)
#define ALL(a)  (a).begin(),(a).end()
#define rALL(a)  (a).rbegin(),(a).rend()

// --- 型定義 & 定数 ---
typedef long long ll;
typedef long double ld;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
const int INF = INT_MAX / 2;
const ll INFL = 1LL << 60;
#define MOD (ll)1000000007
// #define MOD (ll)998244353

template <typename T>
using priority_queue_ascend = priority_queue<T, vector<T>, greater<T>>;

constexpr int DX[] = {1, 0, -1, 0};
constexpr int DY[] = {0, 1, 0, -1};


/*******************************************************/
// 遅延セグ木用
using S = ll;
using F = ll;
const F ID = -1;
S op(S a, S b) { return max(a,b); }
S e() { return 0; }
S mapping(F f, S a) { 
  if(f==ID)return a;
  else return f;
}
F composition(F f, F g) { 
  if(f==ID)return g;
  else return f;
}
F id() { return ID; }
/*******************************************************/


// --- main関数 ---
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    string s;
    cin >> s;
    ll n = s.size();

    auto t = s;
    reverse(ALL(t));

    vector<vector<ll>> ns(n+1,vector<ll>(26,n));
    vector<vector<ll>> nt(n+1,vector<ll>(26,n));

    for(int i=n-1;i>=0;--i){
      rep(j,26){
        ns[i][j] = ns[i+1][j];
        nt[i][j] = nt[i+1][j];
      }
      ns[i][s[i]-'a'] = i;
      nt[i][t[i]-'a'] = i;
    }


    vector<vector<ll>> dp(n+1,vector<ll>(n+1,0LL));
    dp[0][0] = 1;

    rep(i,n+1){
      rep(j,n+1){
        rep(k,26){
          int ni = ns[i][k];
          int nj = nt[j][k];
          if(ni+nj+2 <= n){
            dp[ni+1][nj+1] += dp[i][j];
            dp[ni+1][nj+1] %= MOD;
          }
        }
      }
    }

    ll ans = 0;
    rep(i,n+1){
      for(int j=0;j+i<=n;++j){
        ll num = 1;
        rep(k,26){
          if(ns[i][k]+1+j<=n)++num;
        }
        ans = (ans+dp[i][j]*num%MOD)%MOD;
      }
    }
    cout << ans-1 << endl;
    



    // --- 以下はコメント ---
    
    //小数の桁数の出力指定
    //cout<<fixed<<setprecision(10);
    
    /*
    ostringstream ss;
    ss << setw(n) << std::setfill('0') << h;
    string s = ss.str();
    */

    //vec.assign(n_rows, vector<int>(n_cols, value));

    //a/bの除算の切り上げは(a+(b-1))/b

    //切り捨て除算
    //A,B が負を取り得る場合 A / B - (A % B < 0)

    //ソート(昇順)
    //sort(std::begin(vec), std::end(vec));
    //ソート(降順)
    //sort(std::rbegin(vec), std::rend(vec));

    //while(cin>>num)
    
    //std::*_element は，イテレーターを返すので '*' で値を取得する
    //int min = *std::min_element(vec.begin(), vec.end());
    //int max = *std::max_element(vec.begin(), vec.end());
    //ll sum = std::reduce(std::begin(v), std::end(v));

    return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 35496
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
template<class T> bool chmin(T& a, T b) { return a > b ? a = b, true : false; }
template<class T> bool chmax(T& a, T b) { return a < b ? a = b, true : false; }
template<class T>istream& operator>>(istream& is, vector<T>& v) { for (auto& e : v)is >> e; return is; }
template<class T>ostream& operator<<(ostream& os, vector<T>& v) { for (auto& e : v)os << e << " "; return os; }
using ll = long long;
using ull = unsigned long long;
using uint = unsigned int;
template<class T = ll> struct Edge {
	int to;
	T weight;
	bool operator==(Edge e) { return this->to == e.to and this->weight == e.weight; }
	bool operator<(Edge e) { return this->to < e.to and this->weight < e.weight; }
};
#define SHOW(n) cerr << #n << " = " << n << endl;
#define MSG(x) cerr << x <<endl;

//Atcoder Library
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
//using mint = modint998244353;
using mint = modint1000000007;
//using mint = dynamic_modint<0>;
//using mint = modint;
//mint::set_mod();
static istream& operator>>(istream& is, mint& x) { ll r; cin >> r; x = r; return is; }
static ostream& operator<<(ostream& os, mint& x) { cout << x.val(); return os; }
#endif


int main() {
	cin.tie(nullptr);
	ios::sync_with_stdio(false);

	const int mod = 1e9 + 7;

	string s;
	cin >> s;

	const int n = s.size();

	vector<vector<int>> nexts(n + 1, vector<int>(26, n));
	auto nextt = nexts;

	auto calcnext = [&](vector<vector<int>>& next) {
		for (int i = n - 1; i >= 0; --i) {
			for (int j = 0; j < 26; ++j)next[i][j] = next[i + 1][j];
			next[i][s[i] - 'a'] = i;
		}
		};

	calcnext(nexts);
	reverse(s.begin(), s.end());
	calcnext(nextt);

	vector<vector<int>> dp(n + 1, vector<int>(n + 1));
	dp[0][0] = 1;

	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			for (int k = 0; k < 26; ++k) {
				if (nexts[i][k] + 1 > n or nextt[j][k] + 1 > n)continue;
				dp[nexts[i][k] + 1][nextt[j][k] + 1] += dp[i][j];
				dp[nexts[i][k] + 1][nextt[j][k] + 1] %= mod;
			}
		}
	}

	ll res = 0;
	for (int i = 0; i <= n; ++i) {
		for (int j = 0; i + j <= n; ++j) {
			ll cnt = 1;
			for (int k = 0; k < 26; ++k) {
				if (nexts[i][k] < n - j)++cnt;
			}
			res += dp[i][j] * cnt;
			res %= mod;
		}
	}

	cout << res - 1 << endl;

	return 0;
}
accuracy: 1
time_ms: 300
memory_kb: 19420
final_rank: 4

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 2005

int length;
string input_str,rev_str;
ll dp[NUM][NUM];
int next_loc[NUM][26],rev_next[NUM][26];
ll ruisekiwa[NUM][26],num_alpha[NUM][NUM];

int main(){

	cin >> input_str;

	length = input_str.size();

	rev_str = input_str;

	reverse(rev_str.begin(),rev_str.end());

	for(int i = 0; i < 26; i++){
		next_loc[length][i] = BIG_NUM;
	}

	for(int i = length-1; i >= 0; i--){
		for(int k = 0; k < 26; k++){
			if(input_str[i] == 'a'+k){

				next_loc[i][k] = i;
			}else{

				next_loc[i][k] = next_loc[i+1][k];
			}
		}
	}


	for(int i = 0; i < 26; i++){
		rev_next[length][i] = BIG_NUM;
	}

	for(int i = length-1; i >= 0; i--){
		for(int k = 0; k < 26; k++){
			if(rev_str[i] == 'a'+k){

				rev_next[i][k] = i;
			}else{

				rev_next[i][k] = rev_next[i+1][k];
			}
		}
	}

	for(int i = 0; i <= length; i++){
		for(int k = 0; k <= length; k++){
			dp[i][k] = 0;
		}
	}


	dp[0][0] = 1;
	int next_i,next_rev_i;

	for(int i = 0; i < length; i++){
		for(int rev_i = 0; rev_i < length; rev_i++){
			for(int k = 0; k < 26; k++){

				next_i = next_loc[i][k];
				next_rev_i = rev_next[rev_i][k];

				if(next_i == BIG_NUM || next_rev_i == BIG_NUM || next_i+1+next_rev_i+1 > length)continue;

				dp[next_i+1][next_rev_i+1] += dp[i][rev_i];
				dp[next_i+1][next_rev_i+1] %= MOD;
			}
		}
	}

	ll ans = 0,add;

	for(int i = 0; i <= length; i++){
		for(int rev_i = 0; rev_i+i <= length; rev_i++){
			add = 1;
			for(int k = 0; k < 26; k++){
				if(next_loc[i][k]+1 <= length-(rev_i)){
					add++;
				}
			}
			ans += (dp[i][rev_i]*add)%MOD;
			ans %= MOD;
		}
	}

	printf("%lld\n",ans-1);

	return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 35132
final_rank: 10

code_snippet: #include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

const int MODULO = 1000000007;

// nextIndex[i][c] は、i文字目以降で最初に文字cが登場するインデックスを格納する（存在しない場合は文字列の長さを返す）
vector<vector<int>> computeNextIndices(const string &str) {
    int length = str.size();
    vector<vector<int>> nextIndex(length + 1, vector<int>(26, length));

    // 文字列を逆順に走査し、次に出現する各文字のインデックスを記録する
    for (int i = length - 1; i >= 0; --i) {
        // 現在のインデックスの次の文字インデックスを前の状態から引き継ぐ
        for (int j = 0; j < 26; ++j) {
            nextIndex[i][j] = nextIndex[i + 1][j];
        }
        // 現在の文字の位置を更新
        nextIndex[i][str[i] - 'a'] = i;
    }

    return nextIndex;
}

// aにbを加える関数。MODULOでオーバーフローしないように調整。
void addModulo(long long &a, long long b) {
    a = (a + b) % MODULO;
}

int main() {
    // 入力文字列を受け取る
    string inputString;
    cin >> inputString;

    int stringLength = inputString.size();

    // 逆順にした文字列を作成
    string reversedString = inputString;
    reverse(reversedString.begin(), reversedString.end());

    // 各位置から次に登場する文字のインデックスを計算
    vector<vector<int>> nextIndexForward = computeNextIndices(inputString);
    vector<vector<int>> nextIndexBackward = computeNextIndices(reversedString);

    // DPテーブルを初期化
    vector<vector<long long>> dp(stringLength + 1, vector<long long>(stringLength + 1, 0));
    dp[0][0] = 1;

    // 動的計画法による部分列の数え上げ
    for (int i = 0; i < stringLength; ++i) {
        for (int j = 0; j < stringLength; ++j) {
            // 全てのアルファベットについて調査
            for (int k = 0; k < 26; ++k) {
                int nextForward = nextIndexForward[i][k];
                int nextBackward = nextIndexBackward[j][k];
                
                // 新しいインデックスが文字列の長さを超える場合は無視
                if (nextForward + nextBackward + 2 > stringLength) continue;
                
                // 次の状態へ遷移させる
                addModulo(dp[nextForward + 1][nextBackward + 1], dp[i][j]);
            }
        }
    }

    long long result = 0;

    // すべてのi, jについて結果を集計
    for (int i = 0; i <= stringLength; ++i) {
        for (int j = 0; i + j <= stringLength; ++j) {
            int numOfNextChars = 1;  // 次の文字数の初期値を1に設定

            // 使用可能な次の文字があるかを確認し、カウント
            for (int k = 0; k < 26; ++k) {
                if (nextIndexForward[i][k] + 1 + j <= stringLength) {
                    ++numOfNextChars;
                }
            }

            // 結果に加算。最終的に全体から1を引く。
            result = (result + dp[i][j] * numOfNextChars % MODULO) % MODULO;
        }
    }

    // 結果を出力
    cout << result - 1 << endl;

    return 0;
}
accuracy: 1
time_ms: 170
memory_kb: 35056
final_rank: 6

code_snippet: #line 1 "Library/src/debug.hpp"
#ifdef ONLINE_JUDGE
#define debug(x) void(0)
#else
#define _GLIBCXX_DEBUG
#define debug(x) std::cerr << __LINE__ << " : " << #x << " = " << (x) << std::endl
#endif

/**
 * @brief Debugger
*/
#line 2 "Library/src/math/static_modint.hpp"
#include <cassert>
#include <cstdint>
#include <iostream>

#line 3 "Library/src/internal/type_traits.hpp"
#include <limits>
#include <numeric>
#include <typeinfo>
#line 7 "Library/src/internal/type_traits.hpp"

namespace kyopro {
namespace internal {
template <typename... Args> struct first_enabled {};

template <typename T, typename... Args>
struct first_enabled<std::enable_if<true, T>, Args...> {
    using type = T;
};
template <typename T, typename... Args>
struct first_enabled<std::enable_if<false, T>, Args...>
    : first_enabled<Args...> {};
template <typename T, typename... Args> struct first_enabled<T, Args...> {
    using type = T;
};

template <typename... Args>
using first_enabled_t = typename first_enabled<Args...>::type;

template <int dgt, std::enable_if_t<dgt <= 128>* = nullptr> struct int_least {
    using type = first_enabled_t<std::enable_if<dgt <= 8, std::int8_t>,
                                 std::enable_if<dgt <= 16, std::int16_t>,
                                 std::enable_if<dgt <= 32, std::int32_t>,
                                 std::enable_if<dgt <= 64, std::int64_t>,
                                 std::enable_if<dgt <= 128, __int128_t>>;
};

template <int dgt, std::enable_if_t<dgt <= 128>* = nullptr> struct uint_least {
    using type = first_enabled_t<std::enable_if<dgt <= 8, std::uint8_t>,
                                 std::enable_if<dgt <= 16, std::uint16_t>,
                                 std::enable_if<dgt <= 32, std::uint32_t>,
                                 std::enable_if<dgt <= 64, std::uint64_t>,
                                 std::enable_if<dgt <= 128, __uint128_t>>;
};

template <int dgt> using int_least_t = typename int_least<dgt>::type;
template <int dgt> using uint_least_t = typename uint_least<dgt>::type;

template <typename T>
using double_size_uint_t = uint_least_t<2 * std::numeric_limits<T>::digits>;

template <typename T>
using double_size_int_t = int_least_t<2 * std::numeric_limits<T>::digits>;

struct modint_base {};
template <typename T> using is_modint = std::is_base_of<modint_base, T>;
template <typename T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;


// is_integral
template <typename T>
using is_integral_t =
    std::enable_if_t<std::is_integral_v<T> || std::is_same_v<T, __int128_t> ||
                   std::is_same_v<T, __uint128_t>>;
};  // namespace internal
};  // namespace kyopro

/**
 * @brief Type Traits
 * @see https://qiita.com/kazatsuyu/items/f8c3b304e7f8b35263d8
 */
#line 3 "Library/src/math/gcd.hpp"
#include <cmath>
#include <tuple>
namespace kyopro {
template <typename T> constexpr inline T _gcd(T a, T b) noexcept {
    assert(a >= 0 && b >= 0);
    if (a == 0 || b == 0) return a + b;
    int d = std::min<T>(__builtin_ctzll(a), __builtin_ctzll(b));
    a >>= __builtin_ctzll(a), b >>= __builtin_ctzll(b);
    while (a != b) {
        if (!a || !b) {
            return a + b;
        }
        if (a >= b) {
            a -= b;
            a >>= __builtin_ctzll(a);
        } else {
            b -= a;
            b >>= __builtin_ctzll(b);
        }
    }

    return a << d;
}

template <typename T>
constexpr inline T ext_gcd(T a, T b, T& x, T& y) noexcept {
    x = 1, y = 0;
    T nx = 0, ny = 1;
    while (b) {
        T q = a / b;
        std::tie(a, b) = std::pair<T, T>{b, a % b};
        std::tie(x, nx) = std::pair<T, T>{nx, x - nx * q};
        std::tie(y, ny) = std::pair<T, T>{ny, y - ny * q};
    }
    return a;
}
};  // namespace kyopro

/**
 * @brief gcd
*/
#line 8 "Library/src/math/static_modint.hpp"
namespace kyopro {
template <int _mod, std::enable_if_t<_mod >= 0>* = nullptr>
class modint : internal::modint_base {
    using mint = modint<_mod>;
    using i32 = std::int32_t;
    using u32 = std::uint32_t;
    using i64 = std::int64_t;
    using u64 = std::uint64_t;

    u32 v;
    constexpr u32 normalize(i64 v_) const noexcept {
        v_ %= _mod;
        if (v_ < 0) {
            v_ += _mod;
        }
        return v_;
    }

public:
    static constexpr u32 mod() noexcept { return _mod; }
    constexpr modint() noexcept : v(0) {}
    constexpr modint(i64 v_) noexcept : v(normalize(v_)) {}

    static mint raw(u32 a) {
        mint m;
        m.v = a;
        return m;
    }
    constexpr u32 val() const noexcept { return v; }
    constexpr mint& operator+=(const mint& rhs) noexcept {
        v += rhs.val();
        if (v >= _mod) {
            v -= _mod;
        }
        return (*this);
    }
    constexpr mint& operator-=(const mint& rhs) noexcept {
        v += _mod - rhs.val();
        if (v >= _mod) {
            v -= _mod;
        }
        return (*this);
    }
    constexpr mint& operator*=(const mint& rhs) noexcept {
        v = (u64)v * rhs.val() % _mod;
        return (*this);
    }

    constexpr mint operator+(const mint& r) const noexcept {
        return mint(*this) += r;
    }
    constexpr mint operator-(const mint& r) const noexcept {
        return mint(*this) -= r;
    }
    constexpr mint operator*(const mint& r) const noexcept {
        return mint(*this) *= r;
    }

    constexpr mint& operator+=(i64 rhs) noexcept {
        (*this) += mint(rhs);
        return (*this);
    }
    constexpr mint& operator-=(i64 rhs) noexcept {
        (*this) -= mint(rhs);
        return (*this);
    }
    constexpr mint& operator*=(i64 rhs) noexcept {
        (*this) *= mint(rhs);
        return (*this);
    }
    constexpr friend mint operator+(i64 l, const mint& r) noexcept {
        return mint(l) += r;
    }
    constexpr friend mint operator-(i64 l, const mint& r) noexcept {
        return mint(l) -= r;
    }
    constexpr friend mint operator*(i64 l, const mint& r) noexcept {
        return mint(l) *= r;
    }

    constexpr mint operator+(i64 r) const noexcept { return mint(*this) += r; }
    constexpr mint operator-(i64 r) const noexcept { return mint(*this) -= r; }
    constexpr mint operator*(i64 r) const noexcept { return mint(*this) *= r; }

    constexpr mint& operator=(i64 r) noexcept { return (*this) = mint(r); }

    constexpr bool operator==(const mint& r) const noexcept {
        return (*this).val() == r.val();
    }

    template <typename T, internal::is_integral_t<T>* = nullptr>
    constexpr mint pow(T e) const noexcept {
        mint ans(1), base(*this);
        while (e) {
            if (e & 1) {
                ans *= base;
            }
            base *= base;
            e >>= 1;
        }
        return ans;
    }

    constexpr mint inv() const noexcept {
        long long x, y;
        auto d = ext_gcd((long long)_mod, (long long)v, x, y);
        assert(d == 1);
        return mint(y);
    }

    constexpr mint& operator/=(const mint& r) noexcept {
        return (*this) *= r.inv();
    }
    constexpr mint operator/(const mint& r) const noexcept {
        return mint(*this) *= r.inv();
    }
    constexpr friend mint operator/(const mint& l, i64 r) noexcept {
        return mint(l) /= mint(r);
    }
    constexpr friend mint operator/(i64 l, const mint& r) noexcept {
        return mint(l) /= mint(r);
    }
};
};  // namespace kyopro

/**
 * @brief static modint
 */
#line 2 "Library/src/stream.hpp"
#include <ctype.h>
#include <stdio.h>
#include <string>
#line 6 "Library/src/stream.hpp"

namespace kyopro {

inline void single_read(char& c) {
    c = getchar_unlocked();
    while (isspace(c)) c = getchar_unlocked();
}
template <typename T, internal::is_integral_t<T>* = nullptr>
inline void single_read(T& a) {
    a = 0;
    bool is_negative = false;
    char c = getchar_unlocked();
    while (isspace(c)) {
        c = getchar_unlocked();
    }
    if (c == '-') is_negative = true, c = getchar_unlocked();
    while (isdigit(c)) {
        a = 10 * a + (c - '0');
        c = getchar_unlocked();
    }
    if (is_negative) a *= -1;
}
template <typename T, internal::is_modint_t<T>* = nullptr>
inline void single_read(T& a) {
    long long x;
    single_read(x);
    a = T(x);
}
inline void single_read(std::string& str) noexcept {
    char c = getchar_unlocked();
    while (isspace(c)) c = getchar_unlocked();
    while (!isspace(c)) {
        str += c;
        c = getchar_unlocked();
    }
}
template<typename T>
inline void read(T& x) noexcept {single_read(x);}
template <typename Head, typename... Tail>
inline void read(Head& head, Tail&... tail) noexcept {
    single_read(head), read(tail...);
}

inline void single_write(char c) noexcept { putchar_unlocked(c); }
template <typename T, internal::is_integral_t<T>* = nullptr>
inline void single_write(T a) noexcept {
    if (!a) {
        putchar_unlocked('0');
        return;
    }
    if constexpr (std::is_signed_v<T>) {
        if (a < 0) putchar_unlocked('-'), a *= -1;
    }
    constexpr int d = std::numeric_limits<T>::digits10;
    char s[d + 1];
    int now = d + 1;
    while (a) {
        s[--now] = (char)'0' + a % 10;
        a /= 10;
    }
    while (now <= d) putchar_unlocked(s[now++]);
}
template <typename T, internal::is_modint_t<T>* = nullptr>
inline void single_write(T a) noexcept {
    single_write(a.val());
}
inline void single_write(const std::string& str) noexcept {
    for (auto c : str) {
        putchar_unlocked(c);
    }
}
template <typename T> inline void write(T x) noexcept { single_write(x); }
template <typename Head, typename... Tail>
inline void write(Head head, Tail... tail) noexcept {
    single_write(head);
    putchar_unlocked(' ');
    write(tail...);
}
template <typename... Args> inline void put(Args... x) noexcept {
    write(x...);
    putchar_unlocked('\n');
}
};  // namespace kyopro

/**
 * @brief Fast IO(高速入出力)
 */
#line 2 "Library/src/template.hpp"
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); i++)
#define all(x) std::begin(x), std::end(x)
#define popcount(x) __builtin_popcountll(x)
using i128 = __int128_t;
using ll = long long;
using ld = long double;
using graph = std::vector<std::vector<int>>;
using P = std::pair<int, int>;
constexpr int inf = std::numeric_limits<int>::max() / 2;
constexpr ll infl = std::numeric_limits<ll>::max() / 2;
const long double pi = acosl(-1);
constexpr int dx[] = {1, 0, -1, 0, 1, -1, -1, 1, 0};
constexpr int dy[] = {0, 1, 0, -1, 1, 1, -1, -1, 0};
template <typename T1, typename T2> constexpr inline bool chmax(T1& a, T2 b) {
    return a < b && (a = b, true);
}
template <typename T1, typename T2> constexpr inline bool chmin(T1& a, T2 b) {
    return a > b && (a = b, true);
}

/**
 * @brief Template
*/
#line 5 "a.cpp"

using namespace std;
using namespace kyopro;

using mint = modint<1000000007>;

int main() {
    string s;
    read(s);
    int n = s.size();
    string t = s;  // t=rev(s)
    reverse(all(t));

    const int w = 26;
    vector ns(n + 1, array<int, w>()), nt(n + 1, array<int, w>());

    ns.back().fill(n), nt.back().fill(n);

    for (int i = n - 1; i >= 0; --i) {
        ns[i] = ns[i + 1], nt[i] = nt[i + 1];
        ns[i][s[i] - 'a'] = i;
        nt[i][t[i] - 'a'] = i;
    }

    vector dp(n + 1, vector(n + 1, mint()));

    dp[0][0] = mint::raw(1);

    mint ans = 0;

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            for (int k = 0; k < 26; ++k) {
                int ni = ns[i][k];
                int nj = nt[j][k];
                if (ni + nj + 2 > n) continue;
                dp[ni + 1][nj + 1] += dp[i][j];
            }
        }
    }

    mint res = 0;

    for (int i = 0; i <= n; ++i) {
        for (int j = 0; i + j <= n; ++j) {
            int num = 0;

            for (int k = 0; k < 26; ++k) {
                if (ns[i][k] + 1 + j <= n) ++num;
            }
            
            res += dp[i][j] * (num + 1);
        }
    }

    put(res.val() - 1);
}
accuracy: 1
time_ms: 280
memory_kb: 19168
final_rank: 3

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <string>
#include <vector>
#include <cmath>
#include<sstream>
#include<list>
#include<iomanip>
#include <cstdlib>
#include <cstring>
#include <stack>
#include <bitset>
#include <cassert>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
const int INF = 1000000007;
const long long LINF = 3e18 + 7;
const int MAX_N = 1200010;
const int MAX_W = 600010;
const int MAX_ARRAYK = 100000;
double PI = 3.14159265358979323846;
//using ll = long long; 

// Palindromic Subsequenece
// https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2895
// https://qiita.com/drken/items/a207e5ae3ea2cf17f4bd

long long mod = 1000000007;

vector<vector<long long> > calcNext(string S) {
    int n = S.size();
    vector<vector<long long> > res(n + 1, vector<long long>(26, n));

    for (int i = n - 1; i >= 0; i--) {
        for (int j = 0; j < 26; j++) {
            res[i][j] = res[i + 1][j];
        }
        res[i][S[i] - 'a'] = i;
     }

    return res;
}


int main() {
    
    string S;
    cin >> S;
    
    int n = S.size();

    string T = S;
    reverse(T.begin(), T.end());

    vector<vector<long long> > ns = calcNext(S);
    vector<vector<long long> > nt = calcNext(T);
    vector<vector<long long> > dp(n + 1, vector<long long>(n + 1, 0));

    dp[0][0] = 1;

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < 26; k++) {
                int ni = ns[i][k];
                int nj = nt[j][k];

                if (ni + nj + 2 > n) continue;
                dp[ni + 1][nj + 1] += dp[i][j];
                dp[ni + 1][nj + 1] %= mod;
            }
        }

    }

    long long ans = 0;
    for (int i = 0; i <= n; i++) {
        for (int j = 0; i + j <= n; j++) {
            int num = 1;
            for (int k = 0; k < 26; k++) {
                if (ns[i][k] + 1 + j <= n) {
                    num++; // 奇数長の回文の時の文字の数を足す
                }
            }
            ans = (ans + dp[i][j] * num % mod) % mod;
        }
    }

    cout << ans - 1 << endl;

    
    return 0;
}
accuracy: 1
time_ms: 580
memory_kb: 35156
final_rank: 18

code_snippet: /*

https://onlinejudge.u-aizu.ac.jp/problems/2895

*/
#include<iostream>
#include<set>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<map>
#include<stack>
#include<numeric>
#include<queue>
#include<cmath>
#include<deque>
using namespace std;
typedef long long ll;
const ll INF=1LL<<60;
typedef pair<int,int> P;
typedef pair<int,P> PP;
const ll MOD=1e9+7;
const int inf=1<<30;

vector<vector<int>> nxtc(const string& s){
    int n=s.size();
    vector<vector<int>> res(n+1,vector<int>(26,n+1));

    for(int i=n-1;i>=0;i--){
        for(int c=0;c<26;c++){
            res[i][c]=min(res[i][c],res[i+1][c]);
        }
        res[i][s[i]-'a']=i;
    }
    return res;
}

int main(){
    string S;
    cin>>S;
    int n=S.size();
    string T=S;
    reverse(T.begin(),T.end());

    auto nxtS=nxtc(S);
    auto nxtT=nxtc(T);

    vector<vector<ll>> dp(n+5,vector<ll>(n+5,0));
    dp[0][0]=1;
   
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            for(int c=0;c<26;c++){
                int toi=nxtS[i][c];
                int toj=nxtT[j][c];
                if(toi==n || toj==n) continue;
                if(toi+toj+2<=n){
                    dp[toi+1][toj+1]+=dp[i][j];
                    dp[toi+1][toj+1]%=MOD;
                }

            }
        }
    }
    

    ll ans=0;

    for(int i=0;i<=n;i++){
        for(int j=0;i+j<=n;j++){
            
            int num=0;
            for(int c=0;c<26;c++){
                if(nxtS[i][c]+1+j<=n)num++;
            }
            num++;
            ans+=dp[i][j]*num%MOD;
            ans%=MOD;
        }
    }
    ans--;//空文字
    ans+=MOD;
    ans%=MOD;
        
    cout<<ans<<endl;

    
}
accuracy: 1
time_ms: 180
memory_kb: 35016
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;

const int mod = 1000000007;
int nexl[2009][26];
int nexr[2009][26];
int dp[2009][2009];
bool used[2009][2009];
int N;
string S;

int solve(int cl, int cr) {
    if (cl > cr) return 1;
    if (used[cl][cr] == true) return dp[cl][cr];
    int ans = 1;
    for (int i = 0; i < 26; i++) {
        int ul = nexl[cl][i];
        int ur = nexr[cr][i];
        if (ul > ur) continue;
        ans += 1;
        if (ul < ur) ans += solve(ul + 1, ur - 1);
        ans %= mod;
    }
    dp[cl][cr] = ans;
    used[cl][cr] = true;
    return ans;
}

int main() {
    // Step 1. Input
    cin >> S;
    N = S.size();

    // Step 2. Precount
    for (int i = 0; i <= N + 1; i++) {
        for (int j = 0; j < 26; j++) nexl[i][j] = N + 1;
        for (int j = 0; j < 26; j++) nexr[i][j] = 0;
    }
    for (int i = 1; i <= N; i++) {
        int var = S[i - 1] - 'a';
        nexr[i][var] = i;
        for (int j = 0; j < 26; j++) nexr[i][j] = max(nexr[i][j], nexr[i - 1][j]);
    }
    for (int i = N; i >= 1; i--) {
        int var = S[i - 1] - 'a';
        nexl[i][var] = i;
        for (int j = 0; j < 26; j++) nexl[i][j] = min(nexl[i][j], nexl[i + 1][j]);
    }

    // Step 3. DP
    solve(1, N);
    cout << (dp[1][N] + mod - 1) % mod << endl;
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 22520
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
// clang-format off
#define rep(i, n) for (ll i = 0; i < ll(n); ++i)
#define drep(i, n) for (ll i = ll(n - 1); i >= 0; --i)
#define rng(a) begin(a), end(a)
#define rrng(a) rbegin(a), rend(a)
#define sz(x) (ll)(x).size()
#define cto const auto&
#define popcount(x) __builtin_popcount(x)
#ifdef _DEBUG
#include <debug_print.hpp>
#define deb(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__)
#else
#define deb(...) (static_cast<void>(0))
#endif
template<class T> inline bool chmin(T& x, const T& y) { return x > y ? x = y, 1 : 0; }
template<class T> inline bool chmax(T& x, const T& y) { return x < y ? x = y, 1 : 0; }
template<class T> inline void print_vec(const vector<T>& x) { rep(i, sz(x)) cout << x[i] << " \n"[i+1==sz(x)]; }
template<class T> inline void uniq_vec(vector<T>& x) { sort(rng(x)); x.erase(unique(rng(x)), x.end()); }
inline void YesNo(bool ok) { cout << (ok ? "Yes\n" : "No\n"); }
inline void FASTER_IO() { cin.tie(0)->sync_with_stdio(false); cout << fixed << setprecision(20); }
// clang-format on

template <class T> using PQ = priority_queue<T, vector<T>, greater<T>>;
using ld = long double;
using P = pair<ll, ll>;
constexpr char el = '\n';
constexpr int INF = 1001001001;
constexpr ll LINF = 2e18;
constexpr int mod = 1000000007;

class mint {
    using ll = long long;
    ll x;

public:
    mint(ll x = 0) : x((x % mod + mod) % mod) {}
    mint& operator++() {
        if (++x == mod) x = 0;
        return *this;
    }
    mint& operator--() {
        if (x-- == 0) x += mod;
        return *this;
    }
    mint& operator+=(const mint& a) {
        if ((x += a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator-=(const mint& a) {
        if ((x += mod - a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator*=(const mint& a) {
        (x *= a.x) %= mod;
        return *this;
    }
    mint operator+(const mint& a) const { return mint(*this) += a; }
    mint operator-(const mint& a) const { return mint(*this) -= a; }
    mint operator*(const mint& a) const { return mint(*this) *= a; }
    mint pow(ll t) const {
        mint res = 1, val = x;
        while (t) {
            if (t & 1) res *= val;
            val *= val;
            t >>= 1;
        }
        return res;
    }

    // for prime mod
    mint inv() const { return pow(mod - 2); }
    mint& operator/=(const mint& a) { return *this *= a.inv(); }
    mint operator/(const mint& a) const { return mint(*this) /= a; }

    friend istream& operator>>(istream& is, mint& a) { return is >> a.x; }
    friend ostream& operator<<(ostream& os, const mint& a) { return os << a.x; }
};

int main() {
    FASTER_IO();

    string s;
    cin >> s;
    int n = sz(s);

    string t = s;
    reverse(rng(t));

    auto get_nxt = [n](const string& s) {
        vector res(n + 1, vector(26, n));
        drep(i, n) {
            rep(j, 26) res[i][j] = res[i + 1][j];
            res[i][s[i] - 'a'] = i;
        }
        return res;
    };

    auto nxt_s = get_nxt(s);
    auto nxt_t = get_nxt(t);

    vector dp(n + 1, vector<mint>(n + 1));
    dp[0][0] = 1;
    rep(i, n) rep(j, n) rep(k, 26) {
        int ni = nxt_s[i][k], nj = nxt_t[j][k];
        if (ni + nj + 2 > n) continue;
        dp[ni + 1][nj + 1] += dp[i][j];
    }

    mint ans = 0;
    rep(i, n + 1) {
        for (int j = 0; i + j <= n; j++) {
            int num = 1;
            rep(k, 26) if (nxt_s[i][k] + 1 + j <= n)++ num;
            ans += dp[i][j] * num;
        }
    }
    cout << ans - 1 << el;

    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 35000
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
// clang-format off
#define rep(i, n) for (ll i = 0; i < ll(n); ++i)
#define drep(i, n) for (ll i = ll(n - 1); i >= 0; --i)
#define rng(a) begin(a), end(a)
#define rrng(a) rbegin(a), rend(a)
#define sz(x) (ll)(x).size()
#define cto const auto&
#define popcount(x) __builtin_popcount(x)
#ifdef _DEBUG
#include <debug_print.hpp>
#define deb(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__)
#else
#define deb(...) (static_cast<void>(0))
#endif
template<class T> inline bool chmin(T& x, const T& y) { return x > y ? x = y, 1 : 0; }
template<class T> inline bool chmax(T& x, const T& y) { return x < y ? x = y, 1 : 0; }
template<class T> inline void print_vec(const vector<T>& x) { rep(i, sz(x)) cout << x[i] << " \n"[i+1==sz(x)]; }
template<class T> inline void uniq_vec(vector<T>& x) { sort(rng(x)); x.erase(unique(rng(x)), x.end()); }
inline void YesNo(bool ok) { cout << (ok ? "Yes\n" : "No\n"); }
inline void FASTER_IO() { cin.tie(0)->sync_with_stdio(false); cout << fixed << setprecision(20); }
// clang-format on

template <class T> using PQ = priority_queue<T, vector<T>, greater<T>>;
using ld = long double;
using P = pair<ll, ll>;
constexpr char el = '\n';
constexpr int INF = 1001001001;
constexpr ll LINF = 2e18;
constexpr int mod = 1000000007;


#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif


#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

struct barrett {
    unsigned int _m;
    unsigned long long im;

    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    unsigned int umod() const { return _m; }

    unsigned int mul(unsigned int a, unsigned int b) const {

        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b


        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder

using mint = atcoder::modint;

int main() {
    FASTER_IO();

    string s;
    cin >> s;
    int n = sz(s);

    string t = s;
    reverse(rng(t));

    auto get_nxt = [&](const string& x) {
        vector res(n + 1, vector(26, -1));
        drep(i, n) {
            rep(j, 26) res[i][j] = res[i + 1][j];
            res[i][x[i] - 'a'] = i;
        }
        return res;
    };

    auto nxt_s = get_nxt(s);
    auto nxt_t = get_nxt(t);

    vector dp(n + 1, vector<mint>(n + 1));
    dp[0][0] = 1;
    rep(i, n) rep(j, n) rep(k, 26) {
        int ni = nxt_s[i][k], nj = nxt_t[j][k];
        if (ni == -1 or nj == -1) continue;
        dp[ni + 1][nj + 1] += dp[i][j];
    }

    mint ans = 0;
    rep(i, n + 1) {
        for (int j = 0; i + j <= n; j++) {
            int num = 1;
            rep(k, 26) if (nxt_s[i][k] != -1 and nxt_s[i][k] + 1 + j <= n)++ num;
            ans += dp[i][j] * num;
        }
    }
    cout << (ans - 1).val() << el;

    return 0;
}
accuracy: 0.30952380952380953
time_ms: 190
memory_kb: 19176
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vl = vector<ll>;
using vvl = vector<vl>;
using pl = pair<ll,ll>;
using vp = vector<pl>;
#define rep(i,n) for(ll i=0;i<(ll)(n);++i)
#define reps(i,s,n) for(ll i=(s);i<(ll)(n);++i)
#define rep1(i,n) for(ll i=1;i<=(ll)(n);++i)
template<typename T>inline bool chmax(T &a,T b){return a<b?a=b,true:false;}
template<typename T>inline bool chmin(T &a,T b){return a>b?a=b,true:false;}
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define be(v) (v).begin(),(v).end()
const long long INF = 1e18;
#ifdef DEBUG
#include <debug.hpp>
#endif

const ll MOD=1000000007;
void add(ll &a,ll b){
	a+=b;
	if(a>MOD)a-=MOD;
}
vvl next(string s){
	ll N=s.size();
	vvl ret(N+1,vl(26,N));
	for(ll n=N-1;n>=0;--n){
		rep(c,26)ret.at(n).at(c)=ret.at(n+1).at(c);
		ret.at(n).at(s.at(n)-'a')=n;
	}
	return ret;
}
ll solve(){
	#ifdef DEBUG
	cout << "--- Input ---" << endl;
	#endif
	string S;cin>>S;
	ll N=S.size();
	#ifdef DEBUG
	string ss="z"; S="";
	rep(i,2000) S+="z"; N=S.size();
	cout<<N<<" "<<S<<endl;
	cout << "--- Logic ---" << endl;
	#endif
	vvl ns=next(S);
	string T=S; reverse(be(T));
	vvl nt=next(T);
	vvl dp(N+1,vl(N+1,0));
	dp.at(0).at(0)=1;
	rep(s,N)rep(t,N){
		rep(c,26){
			if(ns.at(s).at(c)+1 + nt.at(t).at(c)+1 > N)continue;
			add(dp.at(ns.at(s).at(c)+1).at(nt.at(t).at(c)+1), dp.at(s).at(t));
		}
	}
#ifdef DEBUG
	cout<<dp;
#endif
	ll ans=0;
	rep(s,N)rep(t,N){
		if(!dp.at(s).at(t))continue;
		ll num=1;
		rep(c,26) if(ns.at(s).at(c) < N-t) ++num; 
		//reps(i,s,N-t){
			//if(ns.at(i).at(S.at(i)-'a') < N-t) ++num;
		ll num2 = dp.at(s).at(t)*num%MOD;
		add(ans,num2);
#ifdef DEBUG
		cout<<"s="<<s<<" t="<<t<<" num="<<num<<" dp="<<dp.at(s).at(t)<<" ans="<<ans<<endl;
#endif
	}
#ifdef DEBUG
	cout << "--- Answer ---" << endl;
#endif
	cout<<ans-1<<endl;
	return true;
}
int main(){
#ifdef DEBUG
	cout << "--- Main ---" << endl;
#endif
	solve();
	//while(solve());
	return 0;
}
//cout << fixed << setprecision(9);
accuracy: 1
time_ms: 280
memory_kb: 35588
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vl = vector<ll>;
using vvl = vector<vl>;
using pl = pair<ll,ll>;
using vp = vector<pl>;
#define rep(i,n) for(ll i=0;i<(ll)(n);++i)
#define reps(i,s,n) for(ll i=(s);i<(ll)(n);++i)
#define rep1(i,n) for(ll i=1;i<=(ll)(n);++i)
template<typename T>inline bool chmax(T &a,T b){return a<b?a=b,true:false;}
template<typename T>inline bool chmin(T &a,T b){return a>b?a=b,true:false;}
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define be(v) (v).begin(),(v).end()
const long long INF = 1e18;
inline ll ipow(ll x,ll p){
	ll ret=x; rep1(i,p-1) ret*=x; return ret;
}
#ifdef DEBUG
#include <debug.hpp>
#endif

vvl nxt(string s){
	ll N=s.size();
	vvl ret(N+1,vl(26,N));
	for(ll n=N-1;n>=0;--n){
		rep(c,26) ret.at(n).at(c)=ret.at(n+1).at(c);
		ret.at(n).at(s.at(n)-'a')=n;
	}
	return ret;
}
const ll MOD=1000000007;
void add(ll &a,ll b){
	a+=b;
	if(a>MOD)a-=MOD;
}
ll solve(){
#ifdef DEBUG
	cout << "--- Input ---" << endl;
#endif
	string S;cin>>S;
	string T=S;
	reverse(be(T));
	ll N=S.size();
	vvl ns=nxt(S);
	vvl nt=nxt(T);
#ifdef DEBUG
	cout<<N<<" "<<S<<" "<<T<<endl<<ns<<nt;
	cout << "--- Logic ---" << endl;
#endif
	vvl dp(N+2,vl(N+2,0));
	dp.at(0).at(0)=1;
	rep(s,N)rep(t,N){
		rep(c,26){
			ll ni=ns.at(s).at(c);
			ll nj=nt.at(t).at(c);
			if(ni+nj+2>N)continue;
			add(dp.at(ni+1).at(nj+1),dp.at(s).at(t));
		}
	}
	ll ans=0;
	rep(s,N)for(ll t=0;s+t<=N;++t){
		ll num=1;
		rep(k,26)if(ns.at(s).at(k)+1+t<=N)++num;
#ifdef DEBUG
		if(dp.at(s).at(t))cout<<"s="<<s<<" t="<<t<<" dp="<<dp.at(s).at(t)<<" num="<<num<<endl;
#endif
		ans=(ans+dp.at(s).at(t)*num%MOD)%MOD;
	}
#ifdef DEBUG
	cout << "--- Answer ---" << endl;
#endif
	cout<<ans-1<<endl;
	return true;
}
int main(){
#ifdef DEBUG
	cout << "--- Main ---" << endl;
#endif
	solve();
	//while(solve());
	return 0;
}
//cout << fixed << setprecision(9);
accuracy: 1
time_ms: 350
memory_kb: 35588
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr ll MOD = 1000000007;


int main() {
    string s; cin >> s;
    vector last(26, (int)s.size());
    vector nxt(s.size(), vector(26, 0));
    for (int i = (int)s.size() - 1 ; i >= 0 ; i--) {
        last[s[i] - 'a'] = i;
        nxt[i] = last;
    }
    last = vector(26, -1);
    vector prv(s.size(), vector(26, -1));
    for (int i = 0 ; i < (int)s.size() ; i++) {
        last[s[i] - 'a'] = i;
        prv[i] = last; 
    }
    vector pos(26, vector(s.size() + 1, 0));
    for (int i = 0 ; i < (int)s.size() ; i++) {
        for (int j = 0 ; j < 26 ; j++) {
            pos[j][i + 1] = pos[j][i] + (s[i] - 'a' == j);
        }
    }
    vector dp(s.size() + 1, vector(s.size() + 1, 0LL));
    dp[0][s.size()] = 1LL;
    ll odd = 0LL;
    for (int range = (int)s.size() ; range > 0 ; range--) {
        for (int l = 0 ; l + range <= (int)s.size() ; l++) {
            int r = l + range;
            for (int i = 0 ; i < 26 ; i++) {
                int nxtl = nxt[l][i], nxtr = prv[r - 1][i];
                if (nxtl != (int)s.size() and nxtr != -1 and nxtl < nxtr) {
                    dp[nxtl + 1][nxtr] += dp[l][r];
                    dp[nxtl + 1][nxtr] %= MOD;
                }
                if (pos[i][r] - pos[i][l] > 0) {
                    odd = (odd + dp[l][r]) % MOD;
                }
            }
        }
    }
    ll even = -1LL;
    for (auto d : dp) for (auto x : d) even = (even + x) % MOD;
    cout << (odd + even) % MOD << endl;
}
accuracy: 1
time_ms: 240
memory_kb: 35320
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr ll MOD = 1000000007;


int main() {
    string s; cin >> s;
    vector last(26, (int)s.size());
    vector nxt(s.size(), vector(26, 0));
    for (int i = (int)s.size() - 1 ; i >= 0 ; i--) {
        last[s[i] - 'a'] = i;
        nxt[i] = last;
    }
    last = vector(26, -1);
    vector prv(s.size(), vector(26, -1));
    for (int i = 0 ; i < (int)s.size() ; i++) {
        last[s[i] - 'a'] = i;
        prv[i] = last; 
    }
    vector pos(26, vector(s.size() + 1, 0));
    for (int i = 0 ; i < (int)s.size() ; i++) {
        for (int j = 0 ; j < 26 ; j++) {
            pos[j][i + 1] = pos[j][i] + (s[i] - 'a' == j);
        }
    }
    vector dp(s.size() + 1, vector(s.size() + 1, 0LL));
    dp[0][s.size()] = 1LL;
    ll odd = 0LL;
    for (int range = (int)s.size() ; range > 0 ; range--) {
        for (int l = 0 ; l + range <= (int)s.size() ; l++) {
            int r = l + range;
            for (int i = 0 ; i < 26 ; i++) {
                int nxtl = nxt[l][i], nxtr = prv[r - 1][i];
                if (nxtl != (int)s.size() and nxtr != -1 and nxtl < nxtr) {
                    dp[nxtl + 1][nxtr] += dp[l][r];
                }
                if (pos[i][r] - pos[i][l] > 0) {
                    odd = (odd + dp[l][r]) % MOD;
                }
            }
        }
    }
    ll even = -1LL;
    for (auto d : dp) for (auto x : d) even = (even + x) % MOD;
    cout << (odd + even) % MOD << endl;
}
accuracy: 0.30952380952380953
time_ms: 190
memory_kb: 35236
final_rank: 20

code_snippet: # include <iostream>
# include <vector>
# include <set>
# include <unordered_set>
using namespace std;

constexpr int MOD = int(1e9) + 7;
constexpr int NIL = -1;

int main() {
   string _s;
   cin >> _s;
   const int n = _s.size();
   vector<int> s(n + 1, -1);
   for (int i = 1; i <= n; i++) {
      s[i] = _s[i - 1] - 'a';
   }

   const int n_alphabets = 'z' - 'a' + 1;
   vector sigma1(n + 2, vector<int>(n_alphabets, NIL));
   vector sigma2(n + 2, vector<int>(n_alphabets, NIL));
   for (int i = 0; i <= n + 1; i++) {
      for (int c = 0; c < n_alphabets; c++) {
         for (int j = i + 1; j <= n; j++) {
            if (s[j] == c) {
               sigma1[i][c] = j;
               break;
            }
         }
         for (int j = i - 1; j >= 0; j--) {
            if (s[j] == c) {
               sigma2[i][c] = j;
               break;
            }
         }
      }
   }

   long long ans = 0;

   vector dp(n + 2, vector<long long>(n + 2, 0));
   dp[0][n + 1] = 1;
   for (int i = 0; i <= n; i++) {
      for (int j = n + 1; j >= 0; j--) {
         for (int x = 0; x < n_alphabets; x++) {
            int ni = sigma1[i][x];
            int nj = sigma2[j][x];
            if (ni == NIL || nj == NIL || ni >= nj) continue;
            (dp[ni][nj] += dp[i][j]) %= MOD;
         }
      }
   }

   for (int i = 1; i <= n; i++) {
      set<int> st;
      for (int j = i + 1; j <= n; j++) {
         int k = st.size() + 1;
         long long value = (dp[i][j] * k) % MOD;
         (ans += value) %= MOD;
         st.insert(s[j]);
      }
   }

   cout << (ans + set<int>(s.begin(), s.end()).size() - 1) % MOD << endl;
}
accuracy: 1
time_ms: 200
memory_kb: 35060
final_rank: 9

code_snippet: #include<bits/stdc++.h>
using namespace std;

#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif


#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

struct barrett {
    unsigned int _m;
    unsigned long long im;

    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    unsigned int umod() const { return _m; }

    unsigned int mul(unsigned int a, unsigned int b) const {

        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b


        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder

using namespace atcoder;
using ll = long long;
using mint = modint1000000007;
string s;
string t;
int n;

vector<vector<int>> last_gen(string &s){
	vector<vector<int>> res(n+1,vector<int>(26,n));
	for(int i = n-1;i>=0;i--){
		for(int j = 0;j<26;j++){
			res[i][j] = res[i+1][j];
		}
		res[i][s[i]] = i;
	}
	return res;
}

mint dp[2020][2020];

void solve(){
	for(auto &i:s)i-='a';
	t = s;
	reverse(t.begin(),t.end());
	auto ns = last_gen(s);
	auto nt = last_gen(t);
	dp[0][0] = 1;
	for(int i = 0;i<n;i++){
		for(int j = 0;j<n;j++){
			for(int k = 0;k<26;k++){
				dp[ns[i][k]+1][nt[j][k]+1] += dp[i][j];
			}
		}
	}
	mint ans = 0;
	for(int i = 0;i<=n;i++){
		for(int j =0;i+j<=n;j++){
			int num = 1;
			for(int k = 0;k<26;k++){
				if(ns[i][k] + 1 + j <= n)num++;
			}
			mint add = dp[i][j] * num;
			ans += dp[i][j] * mint(num);
		}
	}
	/*
	for(int i = 0;i<=n;i++){
		for(int j = 0;j<=n;j++){
			cout<<dp[i][j].val()<<' ';
		}
		cout<<endl;
	}
	*/
	ans--;
	cout<<ans.val()<<endl;
}

signed main(){
	cin.tie(nullptr);
	ios::sync_with_stdio(false);
	cin >> s;
	n = s.size();
	solve();
}
accuracy: 1
time_ms: 170
memory_kb: 19980
final_rank: 2

code_snippet: #include <bits/stdc++.h>
    using namespace std;
    #include <ext/pb_ds/assoc_container.hpp>
    using namespace __gnu_pbds;
    
    template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
    template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
    #define rep(i,n) for (int i = 0; i < (n); ++i)

    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    using P=pair<ll,ll>;
    using tp=tuple<ll,ll,ll>;
    const int INF=1001001001; 
    const ll INFL=1e18;
    const ll mod=1e9+7;
    
    struct mint {
      ll x; 
      mint(ll x=0):x((x%mod+mod)%mod){}
      mint operator-() const { return mint(-x);}
      mint& operator+=(const mint a) {
        if ((x += a.x) >= mod) x -= mod;
        return *this;
      }
      mint& operator-=(const mint a) {
        if ((x += mod-a.x) >= mod) x -= mod;
        return *this;
      }
      mint& operator*=(const mint a) { (x *= a.x) %= mod; return *this;}
      mint operator+(const mint a) const { return mint(*this) += a;}
      mint operator-(const mint a) const { return mint(*this) -= a;}
      mint operator*(const mint a) const { return mint(*this) *= a;}
      mint pow(ll t) const {
        if (!t) return 1;
        mint a = pow(t>>1);
        a *= a;
        if (t&1) a *= *this;
        return a;
      }
       
      mint inv() const { return pow(mod-2);}
      mint& operator/=(const mint a) { return *this *= a.inv();}
      mint operator/(const mint a) const { return mint(*this) /= a;}
     };
      istream& operator>>(istream& is, const mint& a) { return is >> a.x;}
      ostream& operator<<(ostream& os, const mint& a) { return os << a.x;}
      struct combination {
      vector<mint> fact, ifact;
      combination(int n):fact(n+1),ifact(n+1) {
        assert(n < mod);
        fact[0] = 1;
        for (int i = 1; i <= n; ++i) fact[i] = fact[i-1]*i;
        ifact[n] = fact[n].inv();
        for (int i = n; i >= 1; --i) ifact[i-1] = ifact[i]*i;
      }
      mint operator()(int n, int k) {
        if (k < 0 || k > n) return 0;
        return fact[n]*ifact[k]*ifact[n-k];
      }
     } c(200005);

    vector<vector<int>>f(string s){
        int S=s.size();
        vector<vector<int>>pre(S+1,vector<int>(26,-1));
        vector<int>v(26,-1);
        for(int i=0;i<S;i++){
            pre[i]=v;
            v[s[i]-'a']=i;
        }
        pre[S]=v;
        return pre;
    }

    vector<vector<mint>> calc(string s,string t){
        int S=s.size(),T=t.size();
        auto ps=f(s);
        auto pt=f(t);
        vector<vector<mint>>dp(S+5,vector<mint>(T+5));
        vector<vector<mint>>dp2(S+5,vector<mint>(T+5));
        dp2[0][0]=1;
        for(int i=0;i<=S;i++){
            for(int j=0;j<=T;j++){
                if(i==0||j==0){
                    dp[i][j]=1;
                    continue;
                }
                dp[i][j]+=dp[i-1][j];
                dp[i][j]+=dp[i][j-1];
                dp[i][j]-=dp[i-1][j-1];
                if(s[i-1]==t[j-1]){
                    mint cur=0;
                    cur+=dp[i-1][j-1];
                    int ss=ps[i-1][s[i-1]-'a'];
                    int tt=pt[j-1][t[j-1]-'a'];
                    if(ss>=0)cur-=dp[ss][j-1];
                    if(tt>=0)cur-=dp[i-1][tt];
                    if(ss>=0&&tt>=0){cur+=dp[ss][tt];}
                    dp[i][j]+=cur;
                    dp2[i][j]+=cur;
                }
            }
        }
        return dp2;
    }

    void solve(){
        string s;
        cin>>s;
        int S=s.size();
        string t=s;
        reverse(t.begin(),t.end());
        auto dp=calc(s,t);
        auto ps=f(s);
        mint ans=0;
        for(int i=0;i<=S;i++){
            for(int j=0;i+j<=S;j++){
                ll add=1;
                int r=S-j;
                for(int c=0;c<26;c++){
                    if(ps[r][c]>=i&&j+ps[r][c]+1<=S){
                        add++;
                    }
                }
                ans+=dp[i][j]*add;
            }
        }
        cout<<ans-1<<endl;
    }

    int main(){
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);

        solve();
        
        return 0;
    }
accuracy: 1
time_ms: 90
memory_kb: 69560
final_rank: 17

code_snippet: #include <bits/stdc++.h>
    using namespace std;
    #include <ext/pb_ds/assoc_container.hpp>
    using namespace __gnu_pbds;
    
    template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
    template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
    #define rep(i,n) for (int i = 0; i < (n); ++i)

    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    using P=pair<ll,ll>;
    using tp=tuple<ll,ll,ll>;
    const int INF=1001001001; 
    const ll INFL=1e18;
    const ll mod=1e9+7;
    
    struct mint {
      ll x; 
      mint(ll x=0):x((x%mod+mod)%mod){}
      mint operator-() const { return mint(-x);}
      mint& operator+=(const mint a) {
        if ((x += a.x) >= mod) x -= mod;
        return *this;
      }
      mint& operator-=(const mint a) {
        if ((x += mod-a.x) >= mod) x -= mod;
        return *this;
      }
      mint& operator*=(const mint a) { (x *= a.x) %= mod; return *this;}
      mint operator+(const mint a) const { return mint(*this) += a;}
      mint operator-(const mint a) const { return mint(*this) -= a;}
      mint operator*(const mint a) const { return mint(*this) *= a;}
      mint pow(ll t) const {
        if (!t) return 1;
        mint a = pow(t>>1);
        a *= a;
        if (t&1) a *= *this;
        return a;
      }
       
      mint inv() const { return pow(mod-2);}
      mint& operator/=(const mint a) { return *this *= a.inv();}
      mint operator/(const mint a) const { return mint(*this) /= a;}
     };
      istream& operator>>(istream& is, const mint& a) { return is >> a.x;}
      ostream& operator<<(ostream& os, const mint& a) { return os << a.x;}
      struct combination {
      vector<mint> fact, ifact;
      combination(int n):fact(n+1),ifact(n+1) {
        assert(n < mod);
        fact[0] = 1;
        for (int i = 1; i <= n; ++i) fact[i] = fact[i-1]*i;
        ifact[n] = fact[n].inv();
        for (int i = n; i >= 1; --i) ifact[i-1] = ifact[i]*i;
      }
      mint operator()(int n, int k) {
        if (k < 0 || k > n) return 0;
        return fact[n]*ifact[k]*ifact[n-k];
      }
     } c(200005);

    vector<vector<int>>f(string s){
        int S=s.size();
        vector<vector<int>>pre(S+1,vector<int>(26,-1));
        vector<int>v(26,-1);
        for(int i=0;i<S;i++){
            pre[i]=v;
            v[s[i]-'a']=i;
        }
        pre[S]=v;
        return pre;
    }

    vector<vector<mint>> calc(string s,string t){
        int S=s.size(),T=t.size();
        auto ps=f(s);
        auto pt=f(t);
        vector<vector<mint>>dp(S+5,vector<mint>(T+5));
        vector<vector<mint>>dp2(S+5,vector<mint>(T+5));
        dp2[0][0]=1;
        for(int i=0;i<=S;i++){
            for(int j=0;j<=T;j++){
                if(i==0||j==0){
                    dp[i][j]=1;
                    continue;
                }
                dp[i][j]+=dp[i-1][j];
                dp[i][j]+=dp[i][j-1];
                dp[i][j]-=dp[i-1][j-1];
                if(s[i-1]==t[j-1]){
                    mint cur=0;
                    cur+=dp[i-1][j-1];
                    int ss=ps[i-1][s[i-1]-'a'];
                    int tt=pt[j-1][t[j-1]-'a'];
                    if(ss>=0)cur-=dp[ss][j-1];
                    if(tt>=0)cur-=dp[i-1][tt];
                    if(ss>=0&&tt>=0){cur+=dp[ss][tt];}
                    dp[i][j]+=cur;
                    dp2[i][j]+=cur;
                }
            }
        }
        return dp2;
    }

    void solve(){
        string s;
        cin>>s;
        int S=s.size();
        string t=s;
        reverse(t.begin(),t.end());
        auto dp=calc(s,t);
        auto ps=f(s);
        mint ans=0;
        for(int i=0;i<=S;i++){
            for(int j=0;i+j<=S;j++){
                if(dp[i][j].x==0)continue;
                ll add=1;
                int r=S-j;
                for(int c=0;c<26;c++){
                    if(ps[r][c]>=i&&j+ps[r][c]+1<=S){
                        add++;
                    }
                }
                ans+=dp[i][j]*add;
            }
        }
        cout<<ans-1<<endl;
    }

    int main(){
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);

        solve();
        
        return 0;
    }
accuracy: 1
time_ms: 50
memory_kb: 69588
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
#define drep(i, cc, n) for (ll i = (cc); i <= (n); ++i)
#define rep(i, n) drep(i, 0, n - 1)
#define all(a) (a).begin(), (a).end()
#define pb push_back
#define fi first
#define se second

const ll MOD = 1000000007;
const ll MOD2 = 998244353;
const ll INF = 1LL << 60;
const ll MAX_N = 2e5;

int main(){
    string tmp;
    cin >> tmp;

    ll n = (ll)tmp.size();
    string s="$"+tmp+"$";

    vector<vector<ll>> nl(n+2, vector<ll>(26, -INF)), nr(n+2, vector<ll>(26, INF));
    for(ll i=2; i<=n+1; i++){
        for(ll k=0; k<26; k++){
            nl[i][k] = nl[i-1][k];
        }
        nl[i][s[i-1]-'a']=i-1;
    }
    for(ll i=n-1; i>=0; i--){
        for(ll k=0; k<26; k++){
            nr[i][k] = nr[i+1][k];
        }
        nr[i][s[i+1]-'a']=i+1;
    }

    ll ans = 0;
    vector<vector<ll>> dp(n+2, vector<ll>(n+2, 0));
    dp[0][n+1] = 1;
    for(ll l=0; l<=n; l++){
        for(ll r=l+1; r<=n+1; r++){
            for(ll k=0; k<26; k++){
                if(nr[l][k]==INF || nl[r][k]==-INF) continue;
                if(nr[l][k]==r || nl[r][k]==l) continue;
                if(nr[l][k] < nl[r][k]){
                    dp[nr[l][k]][nl[r][k]]+=dp[l][r];
                    dp[nr[l][k]][nl[r][k]]%=MOD;
                }
                if(nr[l][k] <= nl[r][k]){
                    ans += dp[l][r];
                    ans %= MOD;
                }
            }
        }
    }

    rep(i, n+2) rep(j, n+2){
        ans += dp[i][j];
        ans %= MOD;
    }

    cout << (ans + MOD - 1)%MOD << endl;
}
accuracy: 1
time_ms: 210
memory_kb: 35580
final_rank: 11