【BZOJ2803】【POI2012】—Prefixuffix(哈希)

传送门


考虑循环同构一定可以表示成 s 1 + s 2 , s 2 + s 1 s1+s2,s2+s1 s1+s2,s2+s1这样的

考虑枚举 s 1 s1 s1的长度
就变成了求子区间最长相同前后缀

假设当前 S ( i , p ) = S ( n − p − 1 , n − i − 1 ) S(i,p)=S(n-p-1,n-i-1) S(i,p)=S(np1,ni1)
显然有 S ( i + 1 , p − 1 ) = S ( n − p , n − i ) S(i+1,p-1)=S(n-p,n-i) S(i+1,p1)=S(np,ni)
也就是说如果 i i i从大到小枚举最长前后缀最多变大 2 2 2

暴力做就可以了

数据有点强,我的自然溢出双哈希都被卡了
写了取模才过了

#include<bits/stdc++.h>
using namespace std;
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
const ll bas1=131,bas2=97;
const ll mod1=19260817,mod2=19491001;
const int N=1000005;
ll p1[N],p2[N],s1[N],s2[N];
int n;
char s[N];
inline bool has1(int l1,int r1,int l2,int r2){
	return ((s1[r1]-s1[l1-1]*p1[r1-l1+1])%mod1+mod1)%mod1==((s1[r2]-s1[l2-1]*p1[r2-l2+1])%mod1+mod1)%mod1;
}
inline bool has2(int l1,int r1,int l2,int r2){
	return ((s2[r1]-s2[l1-1]*p2[r1-l1+1])%mod2+mod2)%mod2==((s2[r2]-s2[l2-1]*p2[r2-l2+1])%mod2+mod2)%mod2;
}
inline bool check(int l1,int r1,int l2,int r2){
	return has1(l1,r1,l2,r2)&&has2(l1,r1,l2,r2);
}
int main(){
	#ifdef Stargazer
	freopen("lx.cpp","r",stdin);
	#endif
	p1[0]=p2[0]=1;
	for(int i=1;i<N;i++)p1[i]=p1[i-1]*bas1%mod1,p2[i]=p2[i-1]*bas2%mod2;
	n=read();
	scanf("%s",s+1);
	for(int i=1;i<=n;i++)
	s1[i]=(s1[i-1]*bas1+s[i])%mod1,s2[i]=(s2[i-1]*bas2+s[i])%mod2;
	int res=0;
	for(int i=n/2,p=i;i;i--){
		p++,p=min(p,n/2);
		while(check(i,p,n-p+1,n-i+1)==false)p--;
		if(check(1,i-1,n-i+2,n))res=max(res,p);
	}cout<<res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值