[国家集训队] 最长双回文串 题解

题目链接

题目分析

假设 \(x, y\) 都是奇回文串,考虑怎么做:枚举 \(x, y\) 的回文中心 \(i, j\),则必须满足 \(d_i + d_j \ge j - i + 1\),对答案的贡献为 \(2 (j - i)\)。这个东西明显是可以维护的,具体怎么维护我们先不管。

现在考虑 \(x, y\) 中有偶回文串的情况。我们希望能避免复杂的分类讨论,因此尝试在相邻两个字符之间插入分隔符,这样 \(i, j\) 都一定是整数。画一下图可以发现确实不需要分类讨论:条件仍然是 \(d_i + d_j \ge j - i + 1\),但对答案的贡献变成了 \(j - i\)。但是有一个小问题,就是 \(x, y\) 必须非空,因此如果 \(s_i\) 是分隔符的话就必须满足 \(d_i > 1\)。有一个稍微好写的处理方式:我们在串的开头结尾同样插入分隔符,这样如果 \(s_i\) 不是分隔符那么一定有 \(d_i > 1\),因此我们只要判 \(d_i > 1\) 即可。

现在考虑如何维护:限制形如一个二维偏序:\(i < j\),且 \(d_i + d_j \ge j - i + 1\)(移项得 \(i + d_i \ge j - d_j + 1\))。根据 zyh 理论,我们先考虑是否有一维是没用的。因为答案是对 \(j - i\) ckmax,所以当 \(i \ge j\) 时更新不会影响答案,这样我们只剩下一维偏序,排序 + 双指针即可。但是注意到值域只有 \(O(n)\),因此可以直接开桶。

时间复杂度 \(O(n)\)

代码实现

#include <bits/stdc++.h>

#define FOR(i, l, r) for (int i = l; i < (r); ++i)
#define F0R(i, r) FOR (i, 0, r)
#define ROF(i, l, r) for (int i = r; i-- > (l);)
#define R0F(i, r) ROF (i, 0, r)
#define rep(n) F0R (_, n)
#define each(i, x) for (auto& i : x)

using namespace std;

using ll = long long;
using db = long double;
using str = string;

using pi = pair<int, int>;
#define mp make_pair
#define f first
#define s second

#define ttt template <typename T
ttt > using vec = vector<T>;
ttt, size_t n > using arr = array<T, n>;
using vi = vec<int>;
using vb = vec<bool>;
using vl = vec<ll>;
using vpi = vec<pi>;
#define sz(x) int((x).size())
#define all(x) begin(x), end(x)
#define rsz resize
#define pb push_back
#define eb emplace_back

#define il inline
ttt > il bool ckmin(T& x, const T& y) { return y < x ? x = y, true : false; }
ttt > il bool ckmax(T& x, const T& y) { return x < y ? x = y, true : false; }

int main() {
  cin.tie(nullptr)->sync_with_stdio(false), cin.exceptions(cin.failbit);

  str s;
  cin >> s;

  str t = "#";
  each (i, s) t += i, t += "#";

  int n = sz(t);
  vi d(n);
  for (int i = 0, s, r = -1; i < n; ++i) {
    if (i <= r && d[s - i] <= r - i)
      d[i] = d[s - i];
    else {
      d[i] = max(0, r - i + 1);
      while (d[i] <= min(i, n - i - 1) && t[i - d[i]] == t[i + d[i]]) ++d[i];
      if (ckmax(r, i + d[i] - 1)) s = 2 * i;
    }
  }

  vi mx(2 * n, -1e9), mn(2 * n, 1e9);
  F0R (i, n)
    if (d[i] > 1) ckmax(mx[i - d[i] + n], i), ckmin(mn[i + d[i] + n - 1], i);

  int cur = 0, ans = 0;
  F0R (i, 2 * n) ckmax(cur, mx[i]), ckmax(ans, cur - mn[i]);
  cout << ans << "\n";
}
posted @ 2024-03-01 14:25  ClHg2  阅读(20)  评论(1编辑  收藏  举报