文章目录
- 题目描述
- 解析
- 代码
题目描述
解析
看了题解。。。
这题的关键在于可以变换匹配的一个充要条件:
每个字符与前一个相同字符的距离相同
这个搞出来之后就可以以它为关键字进行KMP了
注意!
当与前一个字符的距离超过匹配长度时,是没有意义的,应该当做首次出现处理!
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef unsigned long long ull;
const int N = 1e6+100;
const int M=1e7+5;
const int mod=1e9+7;
int n,m;
int t,c;
int a[N],b[N],st[N],ans;
int last[N],prea[N],preb[N];
int p[N];
int ask(int x,int y){return x<y?x:0;}
void solve(){p[1]=0;for(int i=1,j=0;i<m;i++){while(j&&ask(preb[i+1],j+1)!=ask(preb[j+1],j+1)) j=p[j];if(ask(preb[i+1],j+1)==ask(preb[j+1],j+1)) j++;p[i+1]=j;//printf("i=%d p=%d\n",i+1,j);}
}
void find(){ans=0;for(int i=0,j=0;i<n;i++){while(j&&ask(prea[i+1],j+1)!=ask(preb[j+1],j+1)) j=p[j];if(ask(prea[i+1],j+1)==ask(preb[j+1],j+1)) j++;//printf("i=%d j=%d\n",i+1,j);if(j==m){st[++ans]=i+1-m+1;j=p[j];}}
}
int main(){scanf("%d%d",&t,&c);while(t--){scanf("%d%d",&n,&m);memset(last,0,sizeof(last));for(int i=1;i<=n;i++) scanf("%d",&a[i]);for(int i=1;i<=m;i++) scanf("%d",&b[i]);for(int i=1;i<=n;i++){prea[i]=ask(i-last[a[i]],m);last[a[i]]=i;//printf("i=%d pre=%d\n",i,prea[i]);}memset(last,0,sizeof(last));for(int i=1;i<=m;i++){preb[i]=ask(i-last[b[i]],m);last[b[i]]=i;}solve();find();printf("%d\n",ans);for(int i=1;i<=ans;i++) printf("%d ",st[i]);printf("\n");}return 0;
}