给定字符串 S 和 T。
串A和串B匹配的定义改为:存在一个字符的映射,使得A应用这个映射之后等于B,且这个映射必须为一个排列。
A=121, B=313,当映射为{1->3, 2->1, 3->2}时A'=B,可以匹配
A=212, B=313,当映射为{1->1, 2->3, 3->2}时A'=B,可以匹配
A=232, B=313,当映射为{1->2, 2->3, 3->1}时A'=B,可以匹配
A=123, B=111,当映射为{1->1, 2->1, 3->1}时A'=B,但此时映射不为一个排列,不能匹配
串A和串B匹配的定义改为:存在一个字符的映射,使得A应用这个映射之后等于B,且这个映射必须为一个排列。
A=121, B=313,当映射为{1->3, 2->1, 3->2}时A'=B,可以匹配
A=212, B=313,当映射为{1->1, 2->3, 3->2}时A'=B,可以匹配
A=232, B=313,当映射为{1->2, 2->3, 3->1}时A'=B,可以匹配
A=123, B=111,当映射为{1->1, 2->1, 3->1}时A'=B,但此时映射不为一个排列,不能匹配
求 S 的哪些连续子串与 T 匹配.
这是一个非常巧妙的题,不仅仅实在kmp那个部分
定义lst[x]表示最大的y使得y<x且s[y]=s[x] 若不存在则为0
显然,两个字符串可以匹配,当且仅当两个串的lst数组可以匹配
这里“匹配”指的是A[i]=B[j] 或者 A[i]=0且B[j]>=i 因为文本串长过模板
那么我们的KMP也要按照这个方式来写就行了(当然完全可以用哈希)
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,m,S[1000010],T[1000010],nt[1000010];
int t,ans[1000010],lst[1000010];
int KMP(){
scanf("%d%d",&m,&n); t=0;
memset(lst,-1,sizeof lst);
for(int x,i=0;i<m;++i){
scanf("%d",&x);
if(!~lst[x]) T[i]=0; else T[i]=i-lst[x];
lst[x]=i;
}
memset(lst,-1,sizeof lst);
memset(nt,0,sizeof nt);
for(int x,i=0;i<n;++i){
scanf("%d",&x);
if(!~lst[x]) S[i]=0; else S[i]=i-lst[x];
lst[x]=i;
}
for(int i=1,j;i<n;++i)
for(j=i;j;)
if(S[j=nt[j]]==S[i] || (S[j]==0 && S[i]>j)){ nt[i+1]=j+1; break; }
for(int i=0,j=0;i<m;++i){
if(j<n &&(T[i]==S[j] || (S[j]==0 && T[i]>j))) ++j;
else while(j){
j=nt[j];
if(T[i]==S[j] || (S[j]==0 && T[i]>j)){ ++j; break; }
}
if(j==n) ans[++t]=i-n+1;
}
printf("%d\n",t);
for(int i=1;i<=t;++i) printf("%d ",++ans[i]); puts("");
}
int main(){
freopen("xjz.in","r",stdin);
freopen("xjz.out","w",stdout);
int T; scanf("%d%*d",&T);
while(T--) KMP();
}