【C++】ZZ1848- 解题精讲

【Horn Coding Studio】CPP编程专栏

题目

题目描述

给N个单词串,和一个文章串,求每个单词串是否是文章串的子串,并求每个单词在文章中出现的次数。 文章串长度S:[1,5000] N个单词串总长T:[1,1000000]

输入

第一行一个整数表示N。 第二行一个字符串表示文章串S。 接下来N行每行一个字符串表示单词串。

输出

输出N行,第i行表示第i个单词串出现的次数。

样例输入 复制

2
sdabcad
dab
a

样例输出 复制

1
2

提示

来源

 

一点即通

这道题乍一看……【C++】ZZ1847- 解题精讲 - 冯子坤 - 博客园 (cnblogs.com)再多几次询问不就完事了吗!

然后……T了!

其实一看就不难发现,旧hash算法for在这里至少先要循环500次,再加上至少100000的字符串长度,后果可想而知……(小知识,1s最多可跑完o(1e8)的内容)

 

 这里至少有9个蛋了,另外体量还是1e9*5,自然干不过这道题,不过,我们可以在旧的hash上做一些改动,使其变得简便,不tle

因此…………我还没有想出来……

代码

ZZOJ     TLE

#include <bits/stdc++.h>
using namespace std;
const int p=13131;
const long long mod=1e9+7;
char s1[100005],s2[100005];
long long hash1[100005],hash2[100006],pre[100005];
long long n;
long long idx(char ch) {
    return ch-'a'+1;
}
int main() {
    scanf("%lld",&n);
    scanf("%s",s1+1);
    for(long long i=1; i<=n; i++) {
        scanf("%s",s2+1);
        long long len1=strlen(s1+1);
        long long len2=strlen(s2+1);
        pre[0]=1;
        for(long long i=1; i<=len1; i++) {
            pre[i]=(pre[i-1]*p)%mod;
        }
        for(long long i=1; i<=len1; i++) {
            hash1[i]=(hash1[i-1]*p+idx(s1[i]))%mod;
        }
        for(long long i=1; i<=len2; i++) {
            hash2[i]=(hash2[i-1]*p+idx(s2[i]))%mod;
        }
        long long ans=0;
        for(long long i=1; i+len2-1<=len1; i++) {
            long long le=i;
            long long ri=i+len2-1;
            long long hash=(hash1[ri]-hash1[le-1]*pre[ri-le+1])%mod;
            hash=(hash+mod)%mod;
            if(hash==hash2[len2]) {
                ans++;
            }
        }
        printf("%lld\n",ans);
    }
 
    return 0;
}

 

     

posted @ 2022-06-25 22:34  冯子坤  阅读(29)  评论(0编辑  收藏  举报