[ARG] KMP

  • n,m,C<=1e6
  • 只要两个串中的字符相对位置一样两个串就可以匹配
  • 所以我们可以把原串每个字符改成他和他上次出现位置的距离
  • 做KMP即可
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=1e6+100;
int pre[N],last[N],ans[N],a[N],b[N],cnt,n,m,T,C;
inline int read(){
	int num=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))num=num*10+ch-'0',ch=getchar();
	return num;
}
inline void Print(int x){if(x>9)Print(x/10);putchar(x%10+'0');}
void init(){
	memset(last,0,sizeof(last));
	memset(pre,0,sizeof(pre));
	cnt=0;
}
void KMP(){
	for(int i=2,j=0;i<=n;i++){
		while(j&&min(j+1,a[i])!=a[j+1])j=pre[j];
		if(min(j+1,a[i])==a[j+1])j++;
		pre[i]=j;
	}
	for(int i=1,j=0;i<=m;i++){
		while(j>0&&(j==n||min(j+1,b[i])!=a[j+1]))j=pre[j];
		if(min(j+1,b[i])==a[j+1])j++;
		if(j==n)ans[++cnt]=i-n+1;
	}
	Print(cnt);puts("");
	rep(i,1,cnt)Print(ans[i]),putchar(' ');
	puts("");
}
int main()
{
	T=read(),C=read();
	while(T--){
		init();
		m=read(),n=read();
		rep(i,1,m)b[i]=read();
		rep(i,1,n)a[i]=read();
		rep(i,1,n){int tmp=a[i];a[i]=i-last[a[i]];last[tmp]=i;}
		memset(last,0,sizeof(last));
		rep(i,1,m){int tmp=b[i];b[i]=i-last[b[i]];last[tmp]=i;}
		KMP();
	}return 0;
}

猜你喜欢

转载自blog.csdn.net/strangeDDDF/article/details/88671915
kmp