这里直接利用z函数的信息复用思想,可以达到最优的时间复杂度O(n).

发现可以先得到从每个i开始的st的后缀的LCP的长度,记为数组 b.

难点是得到s[1...i]翻转后与t[1...i]的LCP的长度,记为数组 a:

​ 设已经得到a[i - 1],此时st的末尾分别加上一个s[i]t[i],如果s[i] \neq t[1],那么显然的a[i] = 0;否则设t[1...n]t[2...n]的LCP的长度为z,如果z < x,那么t[2...i]t[1...(i - 1)]的LCP的长度小于x,也就是 $ t[2...i] $ 与s[1...(i - 1)]翻转后的LCP的长度小于x,可以直接得到a[i] = 1 + z;如果z \ge x,那么还要检查一下t[(x + 2)...i]s[1...(i - x - 1)]翻转后的LCP的长度,记为delta,于是$ a[i]=1+x+delta $。

​ 注意这里每次delta的总和不超过n,所以时间复杂度为 $ O(n) $ .

​ 如果觉得上述解释不好懂,可以看下图。C++代码在图下面。

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


int main() {
    int tt; cin >> tt;
    while (tt--) [&]()->void {
        int n; cin >> n;
        string s, t; cin >> s >> t;
        int z = 0;
        while (1 + z < n && t[z] == t[z + 1]) {
            ++z;
        }
        vector<int> a(n), b(n);
        for (int i = n - 1; i >= 0; --i) {
            b[i] = (s[i] == t[i] ? (1 + (i < n - 1 ? b[i + 1] : 0)) : 0);
        }
        a[0] = int(s[0] == t[0]);
        for (int i = 1; i < n; ++i) {
            if (s[i] != t[0]) {
                a[i] = 0;
            } else {
                int x = a[i - 1];
                if (z < x) {
                    a[i] = 1 + z;
                } else {
                    int p = 1 + x;
                    while (p <= i && t[p] == s[i - p]) {
                        ++p;
                    }
                    a[i] = p;
                }
            }
        }
        int mx = 0, p = -1;
        for (int i = 0; i < n; ++i) {
            int cur = a[i];
            if (cur >= i + 1) {
                cur += (i < n - 1 ? b[i + 1] : 0);
            }
            if (cur > mx) {
                mx = cur;
                p = i;
            }
        }
        if (mx == 0) {
            cout << "0 1\n";
        } else {
            cout << mx << ' ' << (p + 1) << '\n';
        }
    }() ;




    return 0;
}