字符串哈希- Anti-Rhyme Pairs UVA - 12338
题意:
T 组 测 试 样 例 , 每 组 样 例 包 括 n 个 字 符 串 , q 组 询 问 , 每 组 询 问 包 含 两 个 数 字 x 、 y , 求 第 x 个 字 符 串 与 第 y 个 字 符 串 的 最 长 公 共 前 缀 的 长 度 。 T组测试样例,每组样例包括n个字符串,q组询问,每组询问包含两个数字x、y,\\求第x个字符串与第y个字符串的最长公共前缀的长度。 T组测试样例,每组样例包括n个字符串,q组询问,每组询问包含两个数字x、y,求第x个字符串与第y个字符串的最长公共前缀的长度。
数据范围:
测 试 样 例 数 T ∈ [ 1 , 35 ] , 字 符 串 个 数 N ∈ [ 1 , 100000 ] , 每 个 字 符 串 长 度 L ∈ [ 1 , 10000 ] , 且 N × L < = 1000000 。 每 组 样 例 询 问 的 数 量 q ∈ [ 1 , 1000000 ] , x , y ∈ [ 1 , N ] 。 测试样例数T∈[1,35],字符串个数N∈[1,100000],每个字符串长度L∈[1,10000],且N×L<=1000000。\\每组样例询问的数量q∈[1,1000000],x,y∈[1,N]。 测试样例数T∈[1,35],字符串个数N∈[1,100000],每个字符串长度L∈[1,10000],且N×L<=1000000。每组样例询问的数量q∈[1,1000000],x,y∈[1,N]。
题解:
首 先 最 暴 力 的 想 到 , 对 每 组 数 据 中 的 每 个 询 问 的 两 个 字 符 串 分 别 哈 希 O ( L ) , 求 最 大 前 缀 O ( L ) 。 时 间 复 杂 度 为 O ( T × q × L ) , 且 q 循 环 中 的 常 数 非 常 大 。 接 着 考 虑 可 以 对 每 组 样 例 先 预 处 理 n 个 字 符 串 的 哈 希 值 , 但 是 由 于 n 与 L 是 不 好 确 定 的 , 并 且 数 组 开 不 了 那 么 大 , 这 个 问 题 可 以 用 v e c t o r 来 解 决 。 时 间 复 杂 度 达 到 了 O ( T × ( q × L + n × L ) ) , 这 时 q × L 仍 然 会 导 致 超 时 。 最 后 想 到 , 求 最 大 前 缀 的 过 程 可 以 利 用 二 分 优 化 到 O ( l o g L ) 。 所 以 , 最 终 的 时 间 复 杂 度 为 O ( T × ( q × l o g L + n × L ) ) = O ( 1 0 7 ) 。 首先最暴力的想到,对每组数据中的每个询问的两个字符串分别哈希O(L),求最大前缀O(L)。\\时间复杂度为O(T×q×L),且q循环中的常数非常大。\\ \ \\接着考虑可以对每组样例先预处理n个字符串的哈希值,但是由于n与L是不好确定的,并且数组开不了那么大,\\这个问题可以用vector来解决。时间复杂度达到了O(T×(q×L+n×L)),这时q×L仍然会导致超时。\\ \ \\最后想到,求最大前缀的过程可以利用二分优化到O(logL)。\\ \ \\所以,最终的时间复杂度为O(T×(q×logL+n×L))=O(10^7)。 首先最暴力的想到,对每组数据中的每个询问的两个字符串分别哈希O(L),求最大前缀O(L)。时间复杂度为O(T×q×L),且q循环中的常数非常大。 接着考虑可以对每组样例先预处理n个字符串的哈希值,但是由于n与L是不好确定的,并且数组开不了那么大,这个问题可以用vector来解决。时间复杂度达到了O(T×(q×L+n×L)),这时q×L仍然会导致超时。 最后想到,求最大前缀的过程可以利用二分优化到O(logL)。 所以,最终的时间复杂度为O(T×(q×logL+n×L))=O(107)。
注意vector的插入操作。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#define ull unsigned long long
#define ll long long
#define inf 0x7fffffff
#define P pair<ull,ull>
using namespace std;
const int N=1e5+10;
const int base=131;
int T,n,q;
char s[10010];
vector<ull> h[N];
int main()
{
scanf("%d",&T);
for(int k=1;k<=T;k++)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
ull tmp=0;
h[i].clear();
h[i].push_back(-inf);
for(int j=1;j<=strlen(s+1);j++)
{
tmp=tmp*base+s[j]-'a';
h[i].push_back(tmp);
}
}
scanf("%d",&q);
int x,y;
printf("Case %d:\n",k);
while(q--)
{
scanf("%d%d",&x,&y);
int l=0,r=min(h[x].size()-1,h[y].size()-1);
while(l<r)
{
int mid=l+r+1>>1;
if(h[x][mid]!=h[y][mid]) r=mid-1;
else l=mid;
}
printf("%d\n",l);
}
}
return 0;
}