CF149E. Martian Strings(KMP/后缀自动机)

题目链接:https://vjudge.net/contest/361017#problem/E
在这里插入图片描述在这里插入图片描述在这里插入图片描述
题意:在一个字符母串中,找到两个不重叠的子串可以拼成要求得到的美好的 字符串。

第一种做法:双向KMP

参考:https://blog.csdn.net/acm_cxlove/article/details/8440574
str为母串,_str为母串的倒序
p为所要找的子串,pp为所要找的子串的倒序
L[i]表示p串中前i个字符在str串中最早出现的位置
R[i]表示pp串中前i个字符在_str串中最早出现的位置
也就是从左边和右边分别找到p串两部分最早出现的位置,然后比较这两部分是否重叠,如果没有重叠的话就满足一种情况

#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 100100
#define inf 1e9
int m;
char str[maxn];
char _str[maxn];
char p[maxn];
char pp[maxn];
int Next[maxn];
int L[maxn];
int R[maxn];
int cnt;
void get_next(char *p,int len)
{
	Next[0]=-1;
	int i=0,j=-1;
	while(i<len)
	{
		if(j==-1||p[i]==p[j])
		{
			i++;j++;
			if(p[i]==p[j])
				Next[i]=Next[j];
			else
				Next[i]=j;
		}
		else
			j=Next[j];
	}
}
void match(char *p,int plen,char *str,int slen,int *dp)
{
	//dp[i]表示p串中前i个字符一同最早出现在str串的第dp[i]个字符串
	//利用了KMP找字符串匹配问题
	int i=0,j=0;
	dp[0]=1;
	while(i<plen&&j<slen)
	{
		if(i==-1||p[i]==str[j])
		{
			i++;j++;
			dp[i]=min(dp[i],j);
		}
		else
			i=Next[i];
		if(i==plen)
			i=Next[i];
	}
}
int main()
{
	scanf("%s",str);
	cin>>m;
	int slen=strlen(str);

	//存储倒序的母串
	for(int i=0;i<slen;i++)
		_str[i]=str[slen-1-i];

	for(int i=0;i<m;i++)
	{
		scanf("%s",p);
		int plen=strlen(p);
		if(plen==1)
			continue;
		//初始化
		memset(Next,0,sizeof(Next));
		for(int j=0;j<=plen;j++)
		{
			L[j]=inf;
			R[j]=inf;
		}
		//处理正常顺序子串与母串
		get_next(p,plen);
		match(p,plen,str,slen,L);

		//pp为p翻转之后的字符串
		for(int j=0;j<plen;j++)
			pp[j]=p[plen-1-j];

		//处理倒序子串与母串
		memset(Next,0,sizeof(Next));
		get_next(pp,plen);
		match(pp,plen,_str,slen,R);

		//遍历每一个点进行匹配
		//L[i]表示p[0]~p[i-1]在母串的最早出现位置
		//R[i]表示p[plen-1]~p[plen-i-2]在母串中从右向左最早出现的位置
		//如果i点处分割开的左串和右串在母串中出现的位置没有交集,则可以
		for(int j=1;j<=plen;j++)
		{
			if(L[j]+R[plen-j]<=slen)
			{
				cnt++;
				break;
			}
		}
	}
	cout<<cnt<<endl;
	return 0;
}

第二种:后缀自动机

后缀自动机我还正在学,后期就补上

原创文章 65 获赞 3 访问量 2114

猜你喜欢

转载自blog.csdn.net/littlegoldgold/article/details/104808558