模板
const int N = 10010,M = 100010;
int n,m;
char p[N],s[M]; //p是匹配串,s是原串
int ne[N];
void get_next(){ //p在s上的匹配数 下标从1开始
ne[1] = 0;
for(int i=2,j=0;i<=lenp;i++){
while(j && p[i] != p[j+1])j = ne[j];
if(p[i] == p[j+1])j++;
ne[i] = j;
}
}
void kmp(){
for(int i=1,j=0;i<=lens;i++){
while(j && s[i] != p[j+1])j = ne[j];
if(s[i] == p[j+1])j++;
//
if(j == lenp){//匹配成功
//printf("%d ",i-lenp+1);
j = ne[j];
}
}
}
int main(){
cin >> n >> p+1 >> m >> s+1;
//求ne[]
get_next();
kmp();
return 0;
}
1.hdu6153
求匹配串的前缀在原串中的出现次数.
int cc,lens,lenp;
char s[MAXN],p[MAXN];
ll ans[MAXN];
int ne[MAXN];
void get_next(){ //p在s上的匹配数
ne[1] = 0;
for(int i=2,j=0;i<=lenp;i++){
while(j && p[i] != p[j+1])j = ne[j];
if(p[i] == p[j+1])j++;
ne[i] = j;
}
}
void kmp(){
for(int i=1,j=0;i<=lens;i++){
while(j && s[i] != p[j+1])j = ne[j];
if(s[i] == p[j+1])j++;
ans[j]++;
if(j == lenp){
j = ne[j];
}
}
}
int main(){
scanf("%d",&cc);
while(cc--){
scanf("%s%s",s+1,p+1);
lens = strlen(s+1);
lenp = strlen(p+1);
reverse(s+1,s+1+lens);
reverse(p+1,p+1+lenp);
memset(ans,0,sizeof(ans));
get_next();kmp();
for(int i=lenp;i>=2;i--)ans[ne[i]] += ans[i];
//i的位置能匹配多少次,ne[i]也能匹配多少次
ll sum = 0;
for(ll i=1;i<=lenp;i++){
sum = (sum + i*ans[i]) % MOD;
}
printf("%lld\n",sum);
}
return 0;
}
2.hdu2594
给你两个字符串,问第一个字符串的前缀和第二个字符串的后缀最长的公共部分.
思路:把这两个字符串拼起来,next[lensum]就是所求的长度.注意:如果这个长度超过了min(len1,len2),有重叠,那么要用ne[ans]更新ans从而找到合理的长度.
int main(){
while(~scanf("%s%s",s+1,p)){
lens = strlen(s+1);
lenp = strlen(p);
int lensum = lens + lenp;
strcat(s+1,p); //放在s里面.
//对s求一遍next
ne[1] = 0;
for(int i=2,j=0;i<=lensum;i++){
while(j && s[i] != s[j+1])j = ne[j];
if(s[i] == s[j+1])j++;
ne[i] = j;
}
int ans = ne[lensum];
while(ans > min(lens,lenp)){
ans = ne[ans];
}
if(ans == 0)printf("0\n");
else{
for(int i=1;i<=ans;i++){
printf("%c",s[i]);
}
printf(" %d\n",ans);
}
}
return 0;
}