牛客小白月赛51 G计算题
题意:长度为
n
n
n的字符串,删除任意一段后缀(可为空),然后必须修改一个字符,求会产生多少回文串.
思路:分奇偶长度讨论回文串的贡献:
回文串长度为奇:
1.本身就是回文串,中心字母可任意修改ans += 26;
2.差一个字符成为回文串,ans += 2;
3.差很多字符
回文串长度为偶:
1.本身就是回文串,只可修改为原字母,ans += 1;
2.差一个字符成为回文串,
a
b
z
c
b
a
abzcba
abzcba, ans += 2;
3.差很多字符
本身是回文串很好判断,哈希一下就可以,差一个字符成为回文串的话,我们可以二分最长的公共前缀 l e n len len,然后会把子串分为两段,继续判断即可。比如 a b c z b z d b a abczbzdba abczbzdba,中心点为 b b b,最长公共前缀 l e n = 2 : z b z len = 2:zbz len=2:zbz,然后继续二分判断 a b 和 b a ab 和 ba ab和ba。
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<ctime>
#include<bitset>
#include<unordered_map>
#include<unordered_set>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f3fll
#define inf 0x3f3f3f3f
#define lowbit(x) x & -x
#define sqr(x) ((x) * (x))
#define pb push_back
#define se second
#define fi first
#define endl '\n'
#define vi vector<int>
#define vl vector<long long>
#define vii vector<pair<int, int>>
// #define int long long
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
template <typename T> void inline re(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
template <typename T> void inline pr(T x) {
if (x < 0) { putchar('-'); pr(-x); return ; }
if (x >= 10) pr(x / 10);
putchar((x % 10) + '0');
}
const int M = 4100, N = 1e6 + 10, mod = 1e9 + 7;
inline ll ksm(ll a, ll b){
ll ans = 1;
for(; b; b >>= 1, a = a * a % mod) if(b & 1) ans = ans * a % mod;
return ans;
}
//----------------------------------------------------------------------------------------//
int n;
char s[N];
ull p[N], hl[N], hr[N];
ull get_hash(ull h[], int l, int r){
return h[r] - h[l - 1] * p[r - l + 1];
}
int query(int x, int y){
int l = 1, r = x;
int res = 0;
while(l <= r){
int mid = l + r >> 1;
if(get_hash(hr, n - x + 1, n - x + mid) == get_hash(hl, y, y + mid - 1)) l = mid + 1, res = mid;
else r = mid - 1;
}
return res;
}
signed main() {
#ifdef JANGYI
freopen("input.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
scanf("%d%s", &n, s + 1);
p[0] = 1;
for(int i = 1; i <= n; i++){
p[i] = p[i - 1] * 131;
hl[i] = hl[i - 1] * 131 + (s[i] - 'a' + 1) ;
}
int k = 1;
for(int i = n; i >= 1; i--){
hr[k] = hr[k - 1] * 131 + (s[i] - 'a' + 1);
k++;
}
// cout << get_hash(hl, 1, 1) << ' ' << get_hash(hr, 1, 1) << '\n';
int ans = 0;
for(int i = 1; i <= n; i++){
if(i & 1){ //奇数长度
int mid = i + 1 >> 1;
int len = query(mid, mid);
// cout << len << endl;
if(len == mid) ans += 26;
else{
int now = query(mid - len - 1, mid + len + 1);
// cout << now << endl;
if(now == mid - len - 1) ans += 2;
}
}else{
int mid1 = i >> 1;
int mid2 = mid1 + 1;
int len = query(mid1, mid2);
// cout << len << endl;
if(len == mid1) ans += 1;
else{
int len_ = query(mid1 - len - 1, mid2 + len + 1);
if(len_ == mid1 - len - 1) ans += 2;
}
}
}
cout << ans;
return 0;
}