题意:
M形字符串指的是由两个相同的回文串拼接而成
给你一个串S,问有多少个前缀是M形字符串
思路:
M形是有两个相同的回文串构成的,所以这个M形串本身就是回文串,我们只需要判断一个串是回文串的同时,他的一半也是回文串即可
那如何判是不是回文串呢,这里我们使用哈希进行判断
如果一个串的正序哈希值等于其逆序哈希,则说明这个串是回文串
哈希的计算方法:
pre[i] = pre[i - 1] * seed + s[i] - 'a' + 1;
对于中间取的一段的哈希值,我们可以利用类似于差分的方法
pre[r] - pre[l - 1] * base[r - l + 1];
乘base[r - l + 1]是为了将其化为“同阶”
AC码:
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using namespace std;
#define inf 0x3f3f3f3f
#define MAX 1500000 + 7
#define endl '\n'
#define seed 1331
const int mod = 1e9 + 7;
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define mem(a,b) memset((a),(b),sizeof(a))
//#define mod 571373;
typedef long long ll ;
//不开longlong见祖宗!
inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}
int pre[MAX], back[MAX], base[MAX];
string s;
ll len;
int idx(char x){
return (int)(x - 'a' + 1);
}
int getpre(int l, int r){//获得区间[l, r]的顺序哈希值
return pre[r] - pre[l - 1] * base[r - l + 1];
}
int getback(int l, int r){//获得区间[l, r]的逆序哈希值
return back[r] - back[l - 1] * base[r - l + 1];
}
bool judge(int i, int j){//判断正逆序的哈希是否相同
return getpre(i, j) == getback(len - j + 1, len - i + 1);
}
int half(int x){
return (x + 1) / 2;
}
int main(){
cin>>s;
s = " " + s;
len = s.size();
base[0] = 1;
for(int i = 1; i <= len; ++i){
base[i] = base[i - 1] * seed;
pre[i] = (pre[i - 1] * seed + idx(s[i]));
back[i] = (back[i - 1] * seed + idx(s[len - i + 1]));
}
int ans = 0;
for(int i = 1; i <= len; ++i){
//如果这个串是回文串,且他的一半也是回文串,就更新答案
if(judge(1, i) && judge(1, half(i)))ans++;
}
cout<<ans<<endl;
return 0;
} 
京公网安备 11010502036488号