Official

E - (∀x∀) Editorial by physics0523


次の事項は、当たり前のことですがこの問題を解くにあたっては非常に重要です。

長さ \(N\) の回文は、先頭 \(\lceil \frac{N}{2} \rceil\) 文字が分かれば一意に定まる。

では、具体例で解法を説明します。
まず、 \(S=\) ABCDE の場合です。 明らかに、先頭 \(3\) 文字が辞書順で ABB 以下であればそこから定まる \(5\) 文字の回文は辞書順で \(S\) 以下です。逆に、先頭 \(3\) 文字が辞書順で ABD 以上であればそこから定まる \(5\) 文字の回文は辞書順で \(S\) より大きいです。
「争点」は先頭 \(3\) 文字が ABC である回文、 ABCBA です。この文字列については先頭 \(3\) 文字の比較では辞書順で \(S\) 以下かどうか分からないため、実際にこの文字列と \(S\) とで比較を行います。今回は、この文字列は辞書順で \(S\) 以下なので条件を満たします。 数えるべきは、先頭 \(3\) 文字が AAA, AAB, …, ABB,ABC である回文の個数であり、これは \(26\) 進数を求める要領 (A\(=0,\) B\(=1,\dots,\) Z\(=25\) と捉えれば \(26\) 進数そのものです)で数えることができます。

次に、 \(S=\) DCBA の場合です。 この場合も先ほど同様の議論ができ、「争点」は先頭 \(2\) 文字が DC である回文(DCCD) です。この場合は、この文字列は辞書順で \(S\) より大きいので条件を満たしません。

結局、以下の \(2\) つができればこの問題を解くことができます。

  • 「争点(すなわち、 \(S\) と先頭 \(\lceil \frac{N}{2} \rceil\) 文字が一致する回文)」より辞書順で前の回文がいくつあるか
  • 「争点」が条件を満たすか

なお、実装の方針によっては

  • 辞書順で「争点」以下の回文がいくつあるか
  • 「争点」が条件を満たさなければ、 \(1\) を引く

という方針を取った方が楽である場合もあります。実装例はこの方針です。

実装例(C++):

#include<bits/stdc++.h>
#define mod 998244353
 
using namespace std;
 
int main(){
  int tc;
  cin >> tc;
  while(tc>0){
    tc--;
    int n;
    string s;
    cin >> n >> s;
    long long cres=0;
    string target=s;
    int p=0,q=n-1;
    while(p<q){
      target[q]=target[p];
      p++;q--;
    }
    int last=(n-1)/2;
    for(int i=0;i<=last;i++){
      cres*=26;cres%=mod;
      cres+=(s[i]-'A');cres%=mod;
    }
    cres++;cres%=mod;
    if(s<target){cres+=(mod-1);cres%=mod;}
    cout << cres << '\n';
  }
  return 0;
}

posted:
last update: