字符串哈希+二分 - Anti-Rhyme Pairs UVA - 12338

字符串哈希- Anti-Rhyme Pairs UVA - 12338

题意:

T 组 测 试 样 例 , 每 组 样 例 包 括 n 个 字 符 串 , q 组 询 问 , 每 组 询 问 包 含 两 个 数 字 x 、 y , 求 第 x 个 字 符 串 与 第 y 个 字 符 串 的 最 长 公 共 前 缀 的 长 度 。 T组测试样例,每组样例包括n个字符串,q组询问,每组询问包含两个数字x、y,\\求第x个字符串与第y个字符串的最长公共前缀的长度。 Tnqxyxy

在这里插入图片描述
数据范围:

测 试 样 例 数 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<=1000000q[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 nnLvectorO(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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值