jzoj3189-解密【字符串hash】

正题


题目大意

一个句子有多个单词。
给出了一个加密了的串。加密方法是将不同的单词转换成不同的单词。然后再给一个加密前的串,求再加密串中可能出现的最早位置。


解题思路

a i a_i ai表示与 i i i相同的前一个字母的位置。
然后根据题目意思对与两个串如果 a a a序列一样那么就是可以转换的加密串。所以我们可以用字符串 h a s h hash hash进行匹配。


c o d e code code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
const ll XJQ=1000000007;
const ll HZB=10007;
const ll p1=9999991;
const ll p2=1000007;
const ll N=1000001;
ll hash1[N],hash2[N],a[N],b[N];
ll len1,len,s,ans;
char c[N];
map<ll,ll> f;
void pre_work(){
	hash1[0]=hash2[0]=1;
	for(ll i=1;i<N;i++){
		hash1[i]=hash1[i-1]*p1%XJQ;
		hash2[i]=hash2[i-1]*p2%XJQ;
	}
}
ll work_in(){
	ll len,s=0,s1=0;
	len=strlen(c);
	for(ll i=0;i<len;i++)
	{
	  	s=(s*26+c[i]-'a')%XJQ;
		s1=(s1*26+c[i]-'a')%HZB;
	}
	return s+s1*XJQ;
}
void init(){
	scanf(" %s",c);
	while(c[0]!='$'){
		ll x=work_in();
		a[++len1]=f[x];
		b[a[len1]]=len1;
		f[x]=len1;
		scanf(" %s",c);
	}
	scanf(" %s",c);
	f.clear();
	while(c[0]!='$'){
		ll x=work_in();
		ll z=f[x];
		++len;
		s=(s*p2)%XJQ;
		if(z)
			(s+=hash1[len-z])%=XJQ;
		f[x]=len;
		scanf(" %s",c);
	}
}
void work(){
	for(ll i=1;i<=len;i++){
	    ans=(ans*p2)%XJQ;
	    if(a[i])
		  (ans+=hash1[i-a[i]])%=XJQ;
	}
	if(ans==s){
		printf("1");
		return;
	}
	ll l=0;
	for(ll i=len+1;i<=len1;i++){
		l++;
		if(b[l]&&b[l]<i)
		  (ans-=hash1[b[l]-l]*hash2[i-b[l]-1]%XJQ-XJQ)%=XJQ;
		ans=(ans*p2)%XJQ;
		if(a[i]&&a[i]>l)
		  (ans+=hash1[i-a[i]])%=XJQ;
		if(l==29767)
		  l++,l--;
		if(ans==s){
			printf("%lld",l+1);
			return;
		}
	}
	printf("0");
}
int main()
{
	freopen("data.in","r",stdin);
	pre_work();
	init();
	work();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值