题目链接:https://ac.nowcoder.com/acm/contest/57322/A
直接枚举会TLE
考虑用字符哈希,用前后缀数组处理好各位的哈希值,每次询问时候判断哈希值大小即可
关于字符串哈希的练习 841. 字符串哈希 - AcWing题库
本题中 t1 是逆序 , t2 是顺序 故要分别求出前后缀数组
for (int i = 1; i <= n; ++ i) {
p[i] = p[i - 1] * P; //对应进位
a[i] = a[i - 1] * P + s[i];// a为前缀数组
}
for (int i = n; i <= n; ++ i)
b[i] = b[i + 1] * P + s[i]; // b为后缀数组
用二分求t1, t2最长相同前缀的长度
然后分四种情况讨论
①t1, t2 完全相同
L == n - R + 1 && len == l
L == n - R + 1表示 t1, t2长度相等;len == l 表示相同前缀长度与t1长度相同
②t1是t2的前缀,则t2字典序更大
L - len + 1 == 1
③t2是t1的前缀,则t1字典序更大
R + len - 1 == n
④t1,t2不满足上述情况,则从相同前缀的后一位开始比较
char c1 = s[L - len], c2 = s[R + len];
if (c1 < c2) cout << "luoluo\n";
else cout << "fanfan\n";
完整代码:
#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define qwq ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
const int N = 1000010, P = 131;
ull p[N], a[N], b[N];
ull getHash1(int l, int r) {
return a[r] - a[l - 1] * p[r - l + 1];
}
ull getHash2(int l, int r) {
return b[l] - b[r + 1] * p[r - l + 1];
}//因为是后缀数组 b[l] 会大于 b[r + 1]
int main(){
qwq; int T;
char s[N];
cin >> s + 1;
cin >> T;
int n = strlen(s + 1);
p[0] = 1;
for (int i = 1; i <= n; ++ i) {
p[i] = p[i - 1] * P; //对应进位
a[i] = a[i - 1] * P + s[i];// a为前缀数组
}
for (int i = n; i >= 1; -- i)
b[i] = b[i + 1] * P + s[i]; // b为后缀数组
while (T -- ) {
int L, R;
cin >> L >> R;
int l = 1, r = min(L, n - R + 1); // 取两端长度中的较小值,避免越界
int len = 0;
while (l <= r) { //二分用于求最长子串长度
int mid = l + r >> 1;
if (getHash1(R, R + mid - 1) == getHash2(L - mid + 1, L)) {
l = mid + 1, len = mid; // 扩展len
} else {
r = mid - 1;
}
}
if (L == n - R + 1 && len == l) //L == n - R + 1表示 t1, t2长度相等
cout << "fanfan\n"; //len == L 表示相同前缀长度与t1长度相同
else if (L - len + 1 == 1) //t1是t2的前缀,则t2字典序更大
cout << "luoluo\n";
else if (R + len - 1 == n)
cout << "fanfan\n";
else {//比较t1, t2 相同前缀的后一个字符
char c1 = s[L - len], c2 = s[R + len];
if (c1 < c2) cout << "luoluo\n";
else cout << "fanfan\n";
}
}
return 0;
}