CF631D Messenger(KMP)

CF631D Messenger

Mean

给你两个字符串\(s,t\),求出\(t\)\(s\)中出现了多少次。

这两个字符串可能会很长,所以字符串被分成很多块,其中\(s\)被分成\(n\)块,\(t\)被分成\(m\)块。每一块\((l,c)\)代表\(l\)\(c\)字符连接在一起组成的字符串。即\((2,′a′)="aa"\)。一个字符串\(ss\)会被表示成一个序列\(((l1,c1),(l2,c2),…,(ln,cn))\)。在输入中字符串"l−c"代表\((l,c)\)

注意到字符串的表示方式不是唯一的,例如\(((1,′a′),(3,′a′))=((2,′a′),(2,′a′))="aaaa"\)

输入格式 第一行有两个整数\(n,m\)

第二行有\(n\)个块,表示字符串\(s\)

第三行有\(m\)个块,表示字符串\(t\)

输出格式 一行一个整数:答案。

Sol

KMP

因为表示方法不唯一,所以需要先将所有连续相同块合并起来。

对于\(lent=1与lent=2\)进行特判。

对于\(lent>=3\),可以观察到匹配成功时头尾不需要严格相同,除去头尾部分严格相同。

那么考虑对除去头尾的\(t\)数组求一个\(Next\),然后做一遍\(KMP\),最后\(check\)的时候再检查一下头尾即可。

Code

#include<bits/stdc++.h>
#define N 500005
using namespace std;
typedef long long ll;
struct node{
	ll cnt;
	char x;
	void print(){
		cout<<cnt<<" - "<<x<<endl;
	}
}t[N],p[N],nt[N],np[N],rp[N];
int nlent,nlenp;
int next1[N];
ll ans=0;
void get_next(node p[],int lenp){
	int j=0;
	for(int i=2;i<=lenp;++i){
		while(j&&(p[j+1].cnt!=p[i].cnt||p[j+1].x!=p[i].x))j=next1[j];
		if(p[j+1].cnt==p[i].cnt&& p[j+1].x==p[i].x)j++;
		next1[i]=j;
	}
}
void kmp(node t[],int lent,node p[],int lenp){
	int j=0;
	for(int i=1;i<=lent;++i){
		while(j&&(p[j+1].cnt!=t[i].cnt||p[j+1].x!=t[i].x))j=next1[j];
		if(p[j+1].cnt==t[i].cnt&&p[j+1].x==t[i].x)j++;
		if(j==lenp){
			// cout<<"i="<<i<<endl;
			if(np[1].cnt<=t[i-lenp].cnt&&np[1].x==t[i-lenp].x && np[nlenp].cnt<=t[i+1].cnt&&np[nlenp].x==t[i+1].x){
				ans++;
			}
			//cout<<i-lenp+1<<endl;//输出p在t中出现的位置
		}
	}
}
void print(int lenp){
	for(int i=1;i<=lenp;++i){
		cout<<next1[i]<<" ";
	}
}
int main(){
	int lent,lenp;
	scanf("%d %d",&lent,&lenp);
	for(int i=1;i<=lent;++i){
		scanf(" %d-%c",&t[i].cnt,&t[i].x);
	}
	for(int i=1;i<=lent;++i){
		int pos = i;
		ll sum = 0;
		while(pos<=lent&&t[pos].x==t[i].x){
			sum += t[pos].cnt;
			pos++;
		}
		nt[++nlent].cnt = sum;
		nt[nlent].x = t[i].x;
		i=pos-1;
	}
	for(int i=1;i<=lenp;++i){
		scanf(" %d-%c",&p[i].cnt,&p[i].x);
	}

	for(int i=1;i<=lenp;++i){
		int pos = i;
		ll sum = 0;
		while(pos<=lenp&&p[pos].x==p[i].x){
			sum += p[pos].cnt;
			pos++;
		}
		np[++nlenp].cnt = sum;
		np[nlenp].x = p[i].x;

		i=pos-1;
	}	
	if(nlenp==1){
		for(int i=1;i<=nlent;++i){
			if(np[1].cnt<=nt[i].cnt&&np[1].x==nt[i].x)ans+=nt[i].cnt-np[1].cnt+1;
		}
	}
	else if(nlenp==2){
		for(int i=1;i<=nlent-1;++i){
			if(np[1].cnt<=nt[i].cnt&&np[1].x==nt[i].x&&np[2].cnt<=nt[i+1].cnt&&np[2].x==nt[i+1].x)ans++;
		}
	}
	else{

		int co=0;
		for(int i=2;i<nlenp;++i){
			rp[++co]=np[i];
		}
		get_next(rp,co);//预处理p的next数组
		kmp(nt,nlent,rp,co);
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2021-09-28 09:31  Qquun  阅读(93)  评论(0)    收藏  举报