【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; }