CodeForces - 113B Petr# (字符串hash)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a54665sdgf/article/details/81782769

题意:给你三个串s,a,b,让你在s中统计前缀为a后缀为b的不同子串的个数。

解法:将三个串的哈希值分别存起来,然后枚举所有的i,j,如果s[i-j]中前缀的哈希值与a相同且后缀的哈希值与b相同,则再检查s[i-j]的哈希值是否被访问过即可。可以先把所有满足要求的j预处理一下,速度可能会快很多。

用字符串hash的方法,决定速度的关键是访问过的hash值如何存储。用vis数组肯定是不行的,因为hash值是unsigned long long类型,数组开不到这么大。

经测试表明,存储hash值的方法,其速度大小排行为set<unordered_set<vector≈hash数组<hash表。

我的测试结果是:用set会超时,用unordered_set勉强过,用vector+sort的方法甚至比用unordered_set还快了两三倍,而且vector的速度和数组相差无几(也有可能是数据量大小的问题)。

最快的方法是用hash表,取字符串hash值的后几位作为数组下标,用链表的方式解决冲突,查询速度飞快。(unordered_set也是通过hash实现的,但速度远无法与手写的hash表相媲美......)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
#define FRER() freopen("i.txt","r",stdin)
#define FREW() freopen("o.txt","w",stdout)

using namespace std;
typedef unsigned long long ll;
const int N=2000+100;
const ll mod=(1<<22)-1;
char s[3][N];
int len[3],R[N],nR;
ll H[3][N],p=1e9+7,P[N];
int head[mod+1],nxt[N*N/2],nmem;
ll num[N*N/2];

ll Hash(int k,int l,int len)
{
    return H[k][l+len]-H[k][l]*P[len];
}

bool Insert(ll x)
{
    int H=x&mod;
    for(int u=head[H]; ~u; u=nxt[u])
        if(num[u]==x)
            return false;
    nxt[nmem]=head[H],num[nmem]=x,head[H]=nmem++;
    return true;
}

int main()
{
    //FRER();
    memset(head,-1,sizeof head);
    nmem=0;
    P[0]=1;
    for(int i=1; i<N; ++i)
        P[i]=P[i-1]*p;
    for(int i=0; i<3; ++i)
    {
        scanf("%s",s[i]);
        len[i]=strlen(s[i]);
    }
    for(int k=0; k<3; ++k)
    {
        H[k][0]=0;
        for(int i=1; i<=len[k]; ++i)
            H[k][i]=H[k][i-1]*p+s[k][i-1];
    }
    ll Ha=Hash(1,0,len[1]);
    ll Hb=Hash(2,0,len[2]);
    nR=0;
    for(int i=0; i+len[2]<=len[0]; ++i)
    {
        if(Hash(0,i,len[2])==Hb)
            R[nR++]=i+len[2];
    }
    int cnt=0;
    for(int i=0; i+len[1]<=len[0]; ++i)
    {
        if(Hash(0,i,len[1])==Ha)
        {
            for(int k=lower_bound(R,R+nR,i+max(len[1],len[2]))-R; k<nR; ++k)
                if(Insert(Hash(0,i,R[k]-i)))++cnt;
        }
    }
    printf("%d\n",cnt);
    return 0;
}
//

猜你喜欢

转载自blog.csdn.net/a54665sdgf/article/details/81782769
今日推荐