HDU 6153 A Secret CCPC网络赛,KMP拓展应用
2017-08-22 11:37
375 查看
传送门:HDU 6153
[align=left]Sample Input[/align]
2
aaaaa
aa
abababab
aba
[align=left]Sample Output[/align]
13
19
题目大意:输入两个字符串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 ,相加并取模即可。
[align=left]Sample Input[/align]
2
aaaaa
aa
abababab
aba
[align=left]Sample Output[/align]
13
19
题目大意:输入两个字符串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; }
相关文章推荐
- 2017中国大学生程序设计竞赛 - 网络选拔赛 HDU 6153 A Secret KMP,思维
- 【KMP+优化】HDU 6153/CCPC 1003 A Secret
- HDU 6153-A Secret(kmp&&ccpc)
- A Secret 2017 CCPC 网络选拔赛 hdu 6153
- HDU 6153 A Secret(拓展KMP)
- hdu 6153 A Secret(kmp||扩展kmp)
- HDU_6153 A Secret【扩展KMP】
- HDU 6153 A Secret (扩展KMP)
- hdu 6153 A Secret (KMP)
- hdu 6153 A Secret(kmp||扩展kmp)
- 【HDU 6153】A Secret (KMP)
- ccpc 2017 网络赛 1004 A Secret (扩展kmp)【模板】
- HDU 6153 A Secret(kmp)
- hdu 6153 A Secret(kmp||扩展kmp)
- HDU-6153---A Secret (扩展kmp)(2017ccpc网络赛)
- hdu 6153 A Secret(KMP)
- hdu 6153 A Secret(kmp||扩展kmp)
- hdu 6153 A Secret KMP
- Hdu 6153 A Secret【KMP】
- HDU 6153 A Secret(KMP变形)