[KMP]一本通(http://ybt.ssoier.cn:8088) 1698:字符串匹配

字符串匹配

【題目描述】數組

對於一個字符集大小爲C的字符串pp,能夠將任意兩個字符在p中的位置進行互換,例如p=12321,交換1212獲得21312,交換14獲得42324,交換能夠進行任意次。若交換後p變成了字符串q,則成qp是匹配的。函數

給定兩個字符集大小爲C的字符串st,求出s中有多少個連續子串與t匹配。spa

【輸入】code

第一行兩個整數TC,分別表示數據組數和字符集大小,字符用1C的整數來表示。blog

對於每組數據:第一行兩個整數nm,分別表示st的長度。字符串

第二行n個正整數表示sget

第三行m個正整數表示tstring

【輸出】it

對於每組數據,輸出包括兩行:io

第一行一個正整數k,表示s中有k個連續子串與t匹配。

第二行從小到大輸出k個數,表示s中與t匹配的連續子串的首位下標(下標從1開始)。

【輸入樣例】

3 3

6 3

1 2 1 2 3 2

3 1 3

6 3

1 2 1 2 1 2

3 1 3

6 3

1 1 2 1 2 1

3 1 3

【輸出樣例】

3

1 2 4

4

1 2 3 4

3

2 3 4

【數據規模及約定】

對於10%的數據,知足n,m,C1000n,m,C1000

對於另外20%的數據,知足n,m105C40n,m105C40

對於另外30%的數據,知足n,m,C105n,m,C105

對於100%的數據,知足1n,m,C106T=31n,m,C106T=3

 

 

【分析】

這其實就是一道KMP的題

題目的難點在於如何交換字符

咱們能夠開一個數組l[1~c]

l[x]表示上一個x出現的位置

a[i]表示字符s[i]離上一個相同字符出現的距離

b[i]表示字符t[i]離上一個相同字符出現的距離

而後就是KMP

難點是如何判斷s[i](t[i])的上一個相同字符是否在模式串以外

這其實很簡單

直接判斷上一個x出現的距離是否大於j不就好了

 

因而開兩個函數

inline int jdg(int x,int l){return x<l?x:0;}//判斷s[i](t[i])的上一個相同字符是否在匹配範圍內
                              //是就返回a[i](b[i]),否就返回0
inline bool eq(int x,int y,int l){return jdg(x,l)==jdg(y,l);}//判斷是否匹配

 經歷千辛萬苦

 

 

【AC代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N (1000000+2)
#define C (1000000+2)
using namespace std;
int p[N];
int a[N],b[N];
int l[C];//這裏很重要,我把C開小了交了不知多少次都沒有過
int ans[N];
template<typename T>inline void read(T& x){
	char temp=getchar();bool u=0;
	for(x=0;temp<'0'||temp>'9';u=temp=='-',temp=getchar());
	for(;temp>='0'&&temp<='9';x=x*10+temp-'0',temp=getchar());
	if(u)x=-x;
	return ;
}//快讀
inline int jdg(int x,int l){return x<l?x:0;}//判斷s[i](t[i])是否在匹配範圍內
                              //是就返回a[i](b[i]),否就返回0
inline bool eq(int x,int y,int l){return jdg(x,l)==jdg(y,l);}//判斷是否匹配
void work(){
	register int i,j,x;
	register int n,m;
	read(n);
	read(m);
	memset(a,0,sizeof a);
	memset(b,0,sizeof b);//有多組數據,必定要初始化
	memset(p,0,sizeof p);//不然就會成爲某dengzhaoxing之二
	memset(l,0,sizeof l);
	for(i=1;i<=n;i++){
		read(x);
		a[i]=i-l[x];//將a[i]賦值爲字符x與上一x之間的距離
		l[x]=i;
	}
	memset(l,0,sizeof l);//輸入s和t以前都要初始化l
	for(i=1;i<=m;i++){
		read(x);
		b[i]=i-l[x];//將b[i]賦值爲字符x與上一x之間的距離
		l[x]=i;
	}
	for(i=1,j=0;i<m;i++){
		while(j&&!eq(b[i+1],b[j+1],j+1))
			j=p[j];
		if(eq(b[i+1],b[j+1],j+1))
			j++;
		p[i+1]=j;
	}//KMP初始化p數組
	for(x=i=j=0;i<n;i++){
		while(j&&!eq(a[i+1],b[j+1],j+1))
			j=p[j];
		if(eq(a[i+1],b[j+1],j+1))
			j++;
		if(j==m){
			ans[++x]=i+2-m;
			j=p[j];
		}
	}//KMP匹配
	printf("%d\n",x);
	for(i=1;i<=x;i++)
		printf("%d ",ans[i]);//輸出答案
	putchar('\n');
	return ;
}
int main(){
	register int t,c,i;
	read(t);
	read(c);
	for(i=1;i<=t;i++)
		work();
	return 0;
}

  

  

相關文章
相關標籤/搜索