HDU 6153 A Secret CCPC网络赛,KMP拓展应用

来源:互联网 发布:影楼后期排版软件 编辑:程序博客网 时间:2024/06/05 15:30

传送门:HDU 6153


Sample Input
2aaaaaaaabababababa
Sample Output
1319

题目大意:输入两个字符串s,t,设长度分别为ls和lt,下标从1开始,求t的所有后缀t[i..lt]在s中出现的次数乘以后缀长度的和。注意,这里的后缀是可重叠的。例如s="abababab",t="aba",后缀aba在s中出现3次,ab出现3次,a出现4次。ans=3*3+3*2+4*1=19.


前置技能:拓展KMP算法,用于求一个串的所有前缀与另一个串的最长公共前缀的长度。比如“abcabac”与“abcb”的最长公共前缀为“abc”。


思路:第一想法是直接用KMP算法求每个后缀在s中出现的次数,然后分别乘以后缀的长度并相加。但是会超时。考虑到我们做了大量的重复运算,可以把s和t字符串都翻转过来得到s'和t'。这样求t的后缀在s中出现的次数就变成了求t'的前缀在s'中出现的次数。当匹配到 i 失配时,说明前 i-1 个前缀都可以匹配,大大减少了重复运算。但是这样一来,原来的KMP算法就不再适用了。因为有些情况是匹配不到的。比如s="acab",t="ab",s'="baca",t'="ba",前缀a在s'中出现了两次,但是却只能匹配到一次。这时可以用拓展KMP算法求出s'的每个前缀和t'的最长公共前缀的长度。当s'的前缀与t'的最长公共前缀长度为n时,说明从当前位置开始有n个前缀可以匹配,他们的长度和为 1+2+…+n = (n+1)*n/2 ,只要将得到的公共前缀的长度求和就好了。


具体实现:先将两个字符串翻转,再调用一次拓展KMP算法求最长公共前缀的长度extend[i],每个最长公共前缀对结果的贡献是 extend[i]*(extend[i]-1)/2 ,相加并取模即可。


#include<stdio.h>#include<string.h>typedef long long LL;int ls,lt;int mod=1e9+7;char s[1000010],t[1000010];int next[1000010],extend[1000010];void get_next(){    int i,a=0,p=0;    next[0]=lt;    for(i=1;i<lt;i++)    {if(i>=p || i+next[i-a]>=p){if(i>=p) p=i;while(p<lt && t[p]==t[p-i]) p++;next[i]=p-i;a=i;}else next[i]=next[i-a];}}void ex_kmp(){int i,a=0,p=0;get_next();for(i=0;i<ls;i++){if(i>=p || i+next[i-a]>=p){if(i>=p) p=i;while(p<ls && p-i<lt && s[p]==t[p-i])p++;extend[i]=p-i;a=i;}else extend[i]=next[i-a];}}int main(){int i,tt;char c;LL ans;scanf("%d",&tt);while(tt--){scanf("%s%s",s,t);ls=strlen(s);lt=strlen(t);for(i=0;i<ls/2;i++){  //将字符串s翻转 c=s[i];s[i]=s[ls-1-i];s[ls-1-i]=c;}for(i=0;i<lt/2;i++){  //将字符串t翻转c=t[i];t[i]=t[lt-1-i];t[lt-1-i]=c;}ex_kmp();  //调用拓展KMP求最长公共前缀 ans=0;for(i=0;i<ls;i++){ //求结果 ans+=((LL)extend[i]*(extend[i]+1)/2)%mod;ans%=mod;}printf("%lld\n",ans);}return 0;}

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小孩子做错事很偏激怎么办 孩子在学校偷钱怎么办 房间墙壁上到处有湿虫怎么办 买了西晒的房子怎么办 墙面瓷砖下水管漏水怎么办 西晒房间开空调没效果怎么办 墙纸被小孩画了怎么办 集成墙板缝隙大怎么办 高血压变低血压怎么办会恢复吗 总是感觉睡不够好困怎么办 两岁宝宝说有鬼怎么办 阳台改成了卧室晒衣服怎么办 室外墙角边墙泥受潮脱落怎么办 新房装修墙体发霉了怎么办 宝宝吃多了发烧怎么办 宝宝睡觉不爱盖被子怎么办 1岁宝宝不盖被子怎么办 2岁宝宝不盖被子怎么办 买的芬琳漆不够刷的怎么办 1.3米宽厨房门怎么办 墙面漆颜色刷深了怎么办 地板上沾了墙漆怎么办 孩子连发高烧8天了怎么办 孩子对数字不敏感怎么办 三岁宝宝不爱学习怎么办 5岁还不认识数字怎么办 小孩上中班还不认识数字怎么办 中班小孩数字都不认识怎么办 中班小孩记不住数字怎么办 中班小孩不肯练数字描红怎么办 2个月吃母乳婴儿缺钙怎么办 月经期接吻水多怎么办 4岁宝宝晚上尿多怎么办 2岁宝宝晚上尿多怎么办 3岁宝宝晚上尿多怎么办 宝宝拉肚子拉绿色的屎怎么办 婴儿吃奶粉大便干燥怎么办 母乳宝宝不拉大便怎么办 我儿子8岁拉肚子怎么办 1岁宝宝经常便秘怎么办 两个月宝宝拉水怎么办