题目链接:https://www.starrycoding.com/problem/163
题目描述
牢 e e e在 S t a r r y C o d i n g StarryCoding StarryCoding的入门教育赛报名单上遇到了许多名字 s 1 , s 2 , . . . , s n s_1, s_2,...,s_n s1,s2,...,sn,他想知道由这些人的名字所构成的集合中,最长公共前缀的长度是多少?
输入格式
第一行一个整数 T ( 1 ≤ T ≤ 1000 ) T(1 \le T \le 1000) T(1≤T≤1000)表示样例个数。
对于每一个样例:
第一行一个整数 n ( 1 ≤ n ≤ 1 0 4 ) n(1 \le n \le 10^4) n(1≤n≤104)表示名单长度。
接下来 n n n行,每行一个字符串表示参赛选手的名字 s i ( 1 ≤ ∣ s i ∣ ≤ 1 0 3 ) s_i(1 \le |s_i| \le 10^3) si(1≤∣si∣≤103),名字仅包含大小写字母和数字,没有空格、换行等符号。
数据保证 1 ≤ ∑ n ≤ 1 0 5 1 \le \sum n \le 10^5 1≤∑n≤105
输出格式
对于每组样例,输出一个整数,表示最长公共前缀的长度。
输入样例1
2
5
starry114514
starry2333
starrycoding
starrabcd
starryhhh
3
sYRuOqnMKs
bgPMcT
MRhMZuxe
输出样例1
5
0
题解
二分 + 字符串进制哈希。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef unsigned long long ull;
const int N = 1e4 + 9;
char s[N][1003];
int n;
const ull base = 131;
ull h[N][1003];
void init(int n)
{
for (int i = 1; i <= n; ++i)
{
int m = strlen(s[i] + 1);
for (int j = 1; j <= m; ++j)
{
h[i][j] = h[i][j - 1] * base + (ull)s[i][j];
}
}
}
bool check(int mid)
{
for (int i = 1; i <= n; ++i)
{
if ((i > 1 && h[i][mid] != h[i - 1][mid]) || strlen(s[i] + 1) < mid)
return false;
}
return true;
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> s[i] + 1;
init(n);
int l = 0, r = 1001;
while (l + 1 != r)
{
int mid = (l + r) >> 1;
if (check(mid))
l = mid;
else
r = mid;
}
cout << l << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _;
cin >> _;
while (_--)
solve();
return 0;
}