单词检索(search)
单词检索(search)
小可可是学校图书馆的管理员,现在他接手了一个十分棘手的任务。
由于学校需要一些材料,校长需要在文章中检索一些信息。校长一共给了小可可N篇文章,每篇文章为一个字符串。现在,校长需要他找到这样的单词,它至少在这N篇文章中的M篇文章里出现过,且单词长度为L。可是,工作量十分庞大,但校长又急需小可可完成这项任务。
现在他向你求助,需要你编写程序完成这项艰巨的任务。
第1行3个正整数N,M,L,表示文章的数目,单词至少出现在M篇文章中和每个单词的长度。
接下来N行,每行一个字符串,表示一篇文章。
仅一行,表示满足检索条件的单词数。
3 2 2
noip
istudycpp
imacppstudent
5
【样例解释】
这5个单词分别为:st,tu,ud,pp,cp。
对于20%的数据有1≤N,M≤10;
对于60%的数据有1≤N,M≤100;
对于100%的数据有1≤N,M≤2000,L≤1000。每篇文章长度不大于1000,均有小写字母组成。
思路
字符串?
既然限定了答案字符的长度,那很容易想到分离字符串,统计出现个数
那就是 级别的个数,空间可以承受
然后怎么存分离出的字符
如果可以
对于每一篇文章,我们把分离的字符去重(因为答案要求的字符至少在N篇文章中的M篇文章里出现过)
最后合在一起
此时统计出现次数超过 的字符数量就是答案
想想,没有问题
关键是分离
如果把每个字符截取下来,那么一片文章处理的复杂度就是
篇就是 的,显然不可以承受
然后呢?
正解
既然有了思路,那就直接打吧(也有 分了)
可是,现在是追求正解的时候
思路中的瓶颈在于分离字符
而我们知道要获取一段区间的信息,如果满足可加性,那就可以前缀和维护
字符串?
哦,哈希!
具体方式
对于一个字符串,我们对其进行哈希时,考虑映射成一个数字
一个很巧妙的方法是:把字符本身当做一串数字,一个字符对应权值
从高到低每一位的位权就参考十进制的方法,记作
其中 为第 位, 是几进制
因为题中字符串均由小写字母构成
所以设为 进制(不这样也行,哈希映射的方法自己选择)
那么对于一个字符串S,有:
截取 S 中后 个字符组成的字符串设为 C',前 个字符组成的字符串设为 C
则
于是维护
双模数,以防万一
代码
#include<cstdio> #include<algorithm> using namespace std; typedef long long LL; const LL p1 = 1e9 + 7 , p2 = 1e9 + 9 , B = 26; LL s1[1005] , s2[1005] , b1[1005] , b2[1005]; struct node{ LL x , y; }d[2000005] , c[2000005]; int cnt , tot , n , m , l , ans; char ch; inline bool cmp(node a , node b){return (a.x < b.x || (a.x == b.x && a.y < b.y));} int main() { scanf("%d%d%d" , &n , &m , &l); b1[0] = b2[0] = 1; for(register int i = 1; i <= 1001; i++) b1[i] = b1[i - 1] * B % p1; for(register int i = 1; i <= 1001; i++) b2[i] = b2[i - 1] * B % p2; int x; for(register int i = 1; i <= n; i++) { x = 0 , s1[0] = 0 , s2[0] = 0 , cnt = 0; ch = getchar(); while (ch < 'a' || ch > 'z') ch = getchar(); for(; ch >= 'a' && ch <= 'z'; ch = getchar()) { x++; s1[x] = (s1[x - 1] * B % p1 + (ch - 'a' + 1)) % p1; s2[x] = (s2[x - 1] * B % p2 + (ch - 'a' + 1)) % p2; if (x >= l) { d[++cnt].x = (s1[x] + p1 - s1[x - l] * b1[l] % p1) % p1; d[cnt].y = (s2[x] + p2 - s2[x - l] * b2[l] % p2) % p2; } } sort(d + 1 , d + cnt + 1 , cmp); c[++tot] = d[1]; for(register int j = 2; j <= cnt; j++) if (d[j].x != d[j - 1].x || d[j].y != d[j - 1].y) c[++tot] = d[j]; } sort(c + 1 , c + tot + 1 , cmp); x = 1; while (x <= tot) { int s = 1; while (c[x].x == c[x + 1].x && c[x].y == c[x + 1].y && x < tot) x++ , s++; if (s >= m) ans++; x++; } printf("%d" , ans); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具