競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 242E

ABC242E

辞書順なので,先頭から決めていくことを考える. 回文なので,真ん中まで決めれば残りは自動で決まる.

桁DPのときに近い. 先頭から文字列を決めていって,既に真に(辞書順で)小さいことが確定しているか否か \(\in Bool\) を保持しながら遷移する. 次に決めようとしているのを \(i\) 文字目とする.

  • 既に真に小さいことが確定しているのなら,次の文字は 26文字から自由に決められる.
  • そうでないときは,次の文字が
    • \(s[i]\) と同じときは,まだ小さいか未確定の状態が続く.
    • \(s[i]\) 未満のときは,真に小さいことが確定する.
    • \(s[i]\) より真に大きいものは選べない.

真ん中まで来たとき,すでに真に小さいと確定している部分はそのまま答えに使える. まだ確定してないとき,本当に回文になっているか個別に確かめる.

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

int main() {
  ll t; cin >> t;
  rep(ti,t){
    ll n; cin >> n;
    string s; cin >> s;

    vector<mint> dp(2);
    dp[0] = 1;
    rep(i, ceil(n,2LL)){
      vector<mint> old(2);
      swap(old, dp);

      dp[0] += old[0];
      dp[1] += old[0]*(s[i]-'A');

      dp[1] += old[1]*26;
    }

    mint ans = dp[1];
    string u = s.substr(0,n/2);
    string t = u;
    if(n%2) t.push_back(s[n/2]);
    reverse(all(u));
    t.insert(t.end(), all(u));
    if(t <= s) ans += 1;
    cout << ans.val() << endl;
  }
 

  return 0;
}