1345: PIPI的字符串问题Ⅲ
题目描述
PIPI双来考查大家字符串处理的能力啦。
给定一个字符串S,以及q次询问。
每次询问给出两个正整数L,R,你需要回答S[L~R]是否为回文串。
输入
第一行给出字符串S,|S|<=1e6. 保证字符串仅由小写字母构成。
第二行给出询问次数q,q<=1e6.
接下来每行给出两个整数L,R,1<=L,R<=|S|.
输出
对于每个询问,若字符串S中[L,R]为回文串,输出YES,否则输出NO。
样例输入
abccba
5
1 6
2 5
3 4
1 3
1 1
样例输出
YES
YES
YES
NO
YES
思路
常规的判别回文串的方法时间复杂度为 o(n),此处有多次询问,肯定会超时。所以使用字符串哈希和双向哈希,判别正向和逆向字符串的哈希值是否相等,若相等则为回文串,判别字符串是否为回文串的时间复杂度为 o(1)。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef unsigned long long ull;
char s[N];
ull Hash_f[N], Hash_r[N], base = 2333;
ull p[N];
int main()
{
scanf("%s", s);
int lens = strlen(s);
//Hash 正向
for(int i = 1; i <= lens; i++)
Hash_f[i] = Hash_f[i - 1] * base + s[i - 1];
// 反向哈希要多体会
for(int i = lens; i >= 1; i--)
Hash_r[i - 1] = Hash_r[i] * base + s[i - 1];
// for(int i = 0; i <= lens; i++)
// cout<<Hash_f[i]<<' ';
// cout<<endl;
// for(int i = 0; i <= lens; i++)
// cout<<Hash_r[i]<<' ';
// cout<<endl;
//获得基数的 k 次方
p[0] = 1;
for(int i = 1; i <= lens; i++) p[i] = p[i - 1] * base;
int q;
scanf("%d", &q);
int l, r;
while(q--)
{
scanf("%d%d", &l, &r);
if(Hash_f[r] - Hash_f[l - 1] * p[r - l + 1] == Hash_r[l - 1] - Hash_r[r] * p[r - l + 1])
printf("YES\n");
else
printf("NO\n");
}
}