HDU 6153 A Secret(拓展KMP)
来源:互联网 发布:成都域名服务器地址 编辑:程序博客网 时间:2024/06/06 00:45
HDU 6153 A Secret
题意
先翻过来,后缀先变前缀(不想描述后缀啦^_^)
给出两个串,这里我们记作S串和T串
对于T串的一个前缀t串,求出t串在S串中出现了多少次,这个小t串对答案的贡献就是”次数 * t的长度”
求T串所有符合条件的前缀对答案的贡献和
解决
- 对拓展KMP没经验^_^,所以现场没写出来,惭愧
- 不管三七二十一,先翻转过来再说…
- 重点,我们求出在S串里,以下标i开始,有多长的字符串可以与T串的前缀完全匹配
- 拓展KMP的extend数组恰好可以找到这个长度
- 知道了每一个位置的匹配长度.我们知道,如果我们匹配到了一个长度为n的串.这个串的每一个前缀的长度都会对答案有一次贡献,而答案恰恰是这些一次次贡献的和.
- 我们利用等差数列求和公式,即可快速求解…
- 为方便理解,用样例来演示一下extend数组
S=ababababT=abasub: 0 1 2 3 4 5 6 7S(reversed): b a b a b a b aextend[i] 0 3 0 3 0 3 0 1extend[1]=3表示:以a(S[1])打头,可以有3个长度去与T串完全匹配extend[7]=1...同理
如果想看extend数组的值是怎么变化的,取消掉注释就可以看到
#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>using namespace std;#define de(x) cout << #x << "=" << x << endlconst int maxn = 1e6+5;const int MOD = 1e9 + 7;int n;char S[maxn],T[maxn];int fail[maxn],extend[maxn]; //next和fail其实是一个意思,都表示失败后回跳到哪里 //但是不知道为什么用next的时候,HDU上会报编译错误/(ㄒoㄒ)/~~//这里用的是kuangbin大神的模板//next[i]:x[i...m-1]与x[0...m-1]的最长公共前缀//extend[i]:y[i...n-1]与x[0...m-1]的最长公共前缀void pre_EKMP(char x[],int m,int fail[]){ fail[0]=m; int j=0; while(j+1<m && x[j]==x[j+1]) j++; fail[1]=j; int k=1; for(int i=2;i<m;i++) { int p=fail[k]+k-1; int L=fail[i-k]; if(i+L<p+1) fail[i]=L; else { j=max(0,p-i+1); while(i+j<m && x[i+j]==x[j]) j++; fail[i]=j; k=i; } }}void EKMP(char x[],int m,char y[],int n,int fail[],int extend[]){ pre_EKMP(x,m,fail); int j=0; while(j<n&&j<m&&x[j]==y[j]) j++; extend[0]=j; int k=0; for(int i=1;i<n;i++) { int p=extend[k]+k-1; int L=fail[i-k]; if(i+L<p+1) extend[i]=L; else { j=max(0,p-i+1); while(i+j<n&&j<m&&y[i+j]==x[j]) j++; extend[i]=j; k=i; } }}int main(){ int cases; scanf("%d",&cases); while(cases--) { scanf("%s",S); scanf("%s",T); int len_s=strlen(S) , len_t=strlen(T); reverse(S,S+len_s); reverse(T,T+len_t); //de(S);de(T); memset(fail,0,sizeof(fail)); memset(extend,0,sizeof(extend)); EKMP(T,len_t,S,len_s,fail,extend); /*for(int i=0;i<len_s;i++) printf("%d%c",extend[i],i==len_s-1?'\n':' ');*/ long long ans=0,tmp,n; for(int i=0;i<len_s;i++) { if(extend[i]) { n=extend[i]%MOD; tmp=(n*(n+1)/2)%MOD; //等差数列求和:n(n+1)/2 ans=(ans+tmp); if(ans>MOD) ans-=MOD; } } cout<<ans<<endl; }}
阅读全文
0 0
- HDU 6153 A Secret(拓展KMP)
- HDU 6153 A Secret(后缀转前缀+拓展KMP)
- HDU 6153 A Secret CCPC网络赛,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
- HDU 6153 A Secret(KMP)
- hdu 6153 A Secret (kmp)
- hdu 6153 A Secret (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&&扩展KMP
- HDU 6153-A Secret(kmp&&ccpc)
- HDU 6153 A Secret(KMP)
- Visual Studio单元测试UnitTest
- 8086CPU寄存器总结
- poj1258 prim算法(模板)
- 201612-2 工资计算
- github之issuse
- HDU 6153 A Secret(拓展KMP)
- gamemaker学习笔记:跳跃
- 前端代码规范
- 系统性能评价
- java.nio.channels.FileChannel源码解读
- Ansible实用案例之批量重装mysql
- Csharp基础整理
- quartz学习3:quartz线程管理
- 刷CCF的算法题(第五天)