問題: 与えられた文字列sについて、左から比較しても右から比較しても辞書順で大きい文字列tを数える。
tの構成を考えると、2つの位置i,j(i≤j)を境界にして、以下のように左から順に5つの部分に分解できる。(2番目と4番目は1文字)
- sと完全一致
- s[i]<t[i]
- 文字自由
- s[j]<t[j]
- sと完全一致
N:=∣s∣とし、0-basedで考える。f(i):= 文字s[i]より大きい文字の数(s[i]=aならf(i)=25)とすると、i,jが異なる場合の数え上げは∑i<jf(i)f(j)26j−i−1である。あとはi,jが一致する場合、つまりsとtがちょうど1字異なる場合を別に数えてf(0)+...+f(N−1)を足す。
上の式を見ると、畳み込める形になっている。g(x)=f(N−x−1)として一方の添え字を逆順にすると、26N−2∑i+j≤N−2f(i)g(j)(1/26)i+jと変形できて、fとgをFFTで畳み込んだ後で1/26を掛けながら加算すればよい。modは109+7だが、登場する数が十分に小さい(高々252⋅105)ので998244353でやっても問題ない。
よく見ると、変形して累積和を取るだけだった。
i<j∑f(i)f(j)26j−i−1=261i=0∑N−1(26if(i)j=i+1∑N−1f(j)26j)
形を見て畳み込みできそうと思えるのは悪くないとしても、変数を分離できないかまず考えるほうがさすがによい気がする。