XTUOJ 1613回文串
回文串#
题目描述#
一个字符串,你可以在这个字符串后面拼接若干个任意字符,使得这个字符串成为回文串。
回文串,即字符串从左到右,从右到左读是一样的。
比如字符串abcbc
,你可以在最后拼接个字符ba
,使得字符串变为回文串abcbcba
,
现在给你一个只含英文小写字母的字符串,请问在后面拼接多少个字符会使得其变成回文串。
输入格式#
第一行是一个整数,表示样例的数量。
每个样例为一个字符串,只含英文小写字母,长度不超过1000。
输出格式#
依次输出每个样例的结果,为一个整数。
样例输入#
复制
3
a
ab
abc
样例输出#
复制
0
1
2
思路
考虑枚举后缀回文串及验证其合法性,第一个成立的即最优解。我们枚举回文串的“后一半部分”的位置,比较它和前一半是不是相等。
题目长度能达到1e6级别,因此我们需要一个高效的比较方法,这个可以通过字符串hash进行比较,通过预处理前缀哈希和后缀哈希可以做到 O ( 1 ) O(1) O(1)比较。
代码
#include <bits/stdc++.h>
#include <chrono>
#include <random>
using namespace std;
#define int long long
using u64 = unsigned long long;
constexpr int N = 2e5 + 10;
constexpr u64 mod = (1ull << 61) - 1;
u64 power[N];
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
uniform_int_distribution<u64> dist(mod / 2, mod - 1);
const u64 base = dist(rng);
u64 add(u64 a, u64 b) {
a += b;
if(a >= mod) a -= mod;
return a;
}
u64 mul(u64 a, u64 b) {
__uint128_t c = __uint128_t(a) * b;
return add(c >> 61, c & mod);
}
u64 merge(u64 h1, u64 h2, int len2) {
return add(mul(h1, power[len2]), h2);
}
void init() {
power[0] = 1;
for(int i = 1; i < N; ++i) {
power[i] = mul(power[i - 1], base);
}
}
vector<u64> build(const string &s) {
int sz = s.size();;
vector<u64> hashed(sz + 1);
for(int i = 0; i < sz; ++i) {
hashed[i + 1] = add(mul(hashed[i], base), s[i]);
}
return hashed;
}
template<typename T>
vector<u64> build(const vector<T> &s) {
int sz = s.size();
vector<u64> hashed(sz + 1);
for(int i = 0; i < sz; ++i) {
hashed[i + 1] = add(mul(hashed[i], base), s[i]);
}
return hashed;
}
u64 query(const vector<u64> &s, int l, int r) {
return add(s[r], mod - mul(s[l - 1], power[r - l + 1]));
}
int lcp(const vector<u64> &a, int l1, int r1, const vector<u64> &b, int l2, int r2) {
int len = min(r1 - l1 + 1, r2 - l2 + 1);
int l = 0, r = len;
int res = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(query(a, l1, l1 + mid - 1) == query(b, l2, l2 + mid - 1)) {
res = mid;
l = mid + 1;
} else r = mid - 1;
}
return res;
}
void solve() {
string s, s1;
cin >> s;
s1 = s;
reverse(s1.begin(), s1.end());
int n = s.size();
auto h1 = build(s), h2 = build(s1);
for(int i = (n + 1) / 2; i <= n; ++i) {
int now = query(h2, 1, n - i + 1);
int len = (n - i + 1);
int l = i - len;
if(l >= 1 && query(h1, l, i - 1) == now) {
cout << n - 2 * len << '\n';
return;
} else if(l >= 0){
l++;
// i + 1, n
if(query(h1, l, i - 1) == query(h2, 1, n - i)) {
cout << n - (2 * len - 1) << '\n';
return;
}
}
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
init();
while(t--) {
solve();
}
return 0;
}
/**************************************************************
Problem: 1613
Language: C++
Result: 正确
****************************************************************/