题意:
给定一个长度为 n n n 的字符串 s s s,对每个 k − s u b s t r i n g ( s k , s k + 1 , ⋯ , s n − k + 1 ) k-substring(s_k, s_{k + 1}, \cdots, s_{n - k + 1}) k−substring(sk,sk+1,⋯,sn−k+1) 求最长的奇数长度 b o r d e r border border。 ( n ≤ 1 0 6 ) (n \leq 10^6) (n≤106)
链接:
https://codeforces.com/problemset/problem/961/F
解题思路:
对单个字符串,可以 k m p kmp kmp 求出最长 b o r d e r border border,但是这里是 ⌈ n 2 ⌉ \lceil\frac{n}{2}\rceil ⌈2n⌉ 个字符串。最长公共前后缀无法直接二分前缀长度来求,但是可以通过枚举前缀的中点 i i i,相应后缀的中点为 n − i + 1 n - i + 1 n−i+1,可以二分最大的 x x x,即得到前缀中点为 i i i 的最长公共前后缀。可以用哈希来快速判断。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e6 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
struct Hash{
const static int md0 = 1e9 + 7, md1 = 1e9 + 9;
int h0, h1;
Hash(int h0 = 0, int h1 = 0) : h0(h0), h1(h1) {}
Hash operator + (const int &o) const { return Hash((h0 + o) % md0, (h1 + o) % md1); }
Hash operator * (const int &o) const { return Hash((h0 * 1ll * o) % md0, (h1 * 1ll * o) % md1); }
Hash operator + (const Hash &o) const { return Hash((h0 + o.h0) % md0, (h1 + o.h1) % md1); }
Hash operator - (const Hash &o) const { return Hash((h0 - o.h0 + md0) % md0, (h1 - o.h1 + md1) % md1); }
Hash operator * (const Hash &o) const { return Hash((h0 * 1ll * o.h0) % md0, (h1 * 1ll * o.h1) % md1); }
bool operator == (const Hash &o) const { return h0 == o.h0 && h1 == o.h1; }
} has[maxn], pw[maxn], base = {131, 133};
vector<pii> G[maxn];
multiset<int> st;
char s[maxn];
int n;
Hash getH(int l, int r){
return has[r] - has[l - 1] * pw[r - l + 1];
}
int judge(int x, int mid){
int lx = x - mid, rx = x + mid;
int y = n - x + 1;
int ly = y - mid, ry = y + mid;
if(lx < 1 || rx > n || ly < 1 || ry > n || rx - lx + 1 == n) return 0;
return getH(lx, rx) == getH(ly, ry);
}
int main() {
ios::sync_with_stdio(0); cin.tie(0);
cin >> n >> s + 1;
pw[0] = {1, 1};
for(int i = 1; i <= n; ++i){
pw[i] = pw[i - 1] * base;
has[i] = has[i - 1] * base + s[i];
}
for(int i = 1; i <= n / 2; ++i){
int l = 0, r = n, mid, ret = -1;
while(l <= r){
mid = gmid;
if(judge(i, mid)) l = mid + 1, ret = mid;
else r = mid - 1;
}
if(ret == -1) continue;
G[i - ret].pb({i, 1});
G[i + 1].pb({i, -1});
}
int lim = (n + 1) / 2;
for(int i = 1; i <= lim; ++i){
for(auto &e : G[i]){
if(e.second == 1) st.insert(e.first);
else st.erase(st.find(e.first));
}
if(!sz(st)) cout << "-1 ";
else{
int mx = *st.rbegin();
int ret = 2 * mx - 2 * i + 1;
cout << ret << " ";
}
}
return 0;
}