2019.3.30 提高A组 T3 JZOJ 3189 解密

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/89001725

D e s c r p t i o n Descrption

手打一个代码比较相似度的程序

给定两个串,现在假设某个串会代替某个串,求从哪个位置开始正好匹配成功

数据范围: n 1 0 6 n\leq 10^6


S o l u t i o n Solution

k m p kmp 字符串模式匹配

但是我们不能直接 k m p kmp ,因为我们不知道每个字符串到底代表这什么

但是我们可以求出之前与它相同的串的间隔距离(用 h a s h hash 求),以此分别作为 a i a_i b i b_i ,再进行 k m p kmp 即可

不过要特判可以直接对上的情况


C o d e Code

#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#define LL long long
#define WYC 200560490131ll
#define ZYC 999983
#define N 1000010
using namespace std;
LL e[N],h[N*2],cx[N],t;
int a[N],b[N],next[N],pre,n,m,j;
char s[N];
inline int hash(LL x,int n)
{
	LL y=x%ZYC;
	while(h[y])
	{
		if(h[y]==x)
		{
			int t=cx[y];//取出之前出现的位置
			cx[y]=n;//放入现在的位置
			return t;
		}
		y=(y+1)%2000000;
	}
	h[y]=x;cx[y]=n;
	return 0;
}
signed main()
{
	e[0]=1;
	for(register int i=1;i<=1000000;i++) e[i]=e[i-1]*27%WYC;
	while(scanf("%s",s+1),s[1]!='$')
	{
		n++;
		t=0;
		for(register int i=1;i<=strlen(s+1);i++) t=(t+(s[i]-96)*e[i-1]%WYC)%WYC;
		pre=hash(t,n);
		if(!pre) a[n]=pre;else a[n]=n-pre;
	}
	scanf("\n");
	memset(h,0,sizeof(h));memset(cx,0,sizeof(cx));
	while(scanf("%s",s+1),s[1]!='$')
	{
		m++;
		t=0;
		for(register int i=1;i<=strlen(s+1);i++) t=(t+(s[i]-96)*e[i-1]%WYC)%WYC;
		pre=hash(t,m);
		if(!pre) b[m]=pre;else b[m]=m-pre;
	}
	j=0;
	for(register int i=2;i<=m;i++)
	{
		while(j&&b[j+1]!=b[i]) j=next[j];
		if(b[j+1]==b[i]) j++;
		next[i]=j;
	}
	j=0;
	for(register int i=1;i<=n;i++)
	{
		while(j&&!(b[j+1]==a[i]||(b[j+1]==0&&a[i]>j))) j=next[j];
		if(b[j+1]==a[i]||(b[j+1]==0&&a[i]>j)) j++;//后面那个括号是特判
		if(j==m) return printf("%d\n",i-m+1)&0;
	}
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/89001725
今日推荐