题目:
给N个字符串,Q组询问,每次询问(i,j),输出第 i 个串和第 j 个串的最长公共前缀长度。
N <= 1e5 ,L <= 1e4, N * L <= 1e6
分析:
这道题二分加字符串哈希很容易想到,没什么可说的。
两个注意的点:
- 字符串的N和L给的很不舒服,没法直接开二位数组,可以考虑用string和vector。或者,把所有字符串存到一个1e6的一维数组中,只不过需要记录每个字符串的起点。
- 做这个题的时候发现,若定义太多函数,比如makeHash(),getHash(),solve(),即使参数都是引用,也会超时。只写一个主函数会省很多很多时间。
代码:
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
#define ms(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
const int MAXN=1e5+5;
const double EPS=1e-8;
const int INF=0x3f3f3f3f;
const int base = 163;
string s[MAXN];
vector<ull> v[MAXN];
ull p[MAXN];
int N,Q;
int main(){
cin.sync_with_stdio(false);
int T,kase = 1;
p[0] = 1;
for(int i=1;i<=MAXN;i++) p[i] = p[i-1] *base;
cin >> T;
while(T--){
cin >> N;
for(int i=1;i<=N;i++){
cin >> s[i];
int n = s[i].size();
v[i].clear();
v[i].push_back(0);
for(int j=1;j<=n;j++){
v[i].push_back(v[i][j-1] * base + s[i][j-1] - 'a' + 1);
}
}
cin >> Q;
cout << "Case "<<kase ++ <<":" << endl;
while(Q--){
int a,b;
cin >> a >> b;
int ans = 0;
int l = 0,r = min(v[a].size(),v[b].size())-1;
while(l<=r){
int mid = (l+r)/2;
if(v[a][mid] == v[b][mid]){
ans = mid;
l = mid + 1;
}else{
r = mid -1;
}
}
cout << ans << endl;
}
}
return 0;
}