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

传送门


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

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

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

暴力做就可以了

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

#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;
}
posted @ 2019-07-15 17:49  Stargazer_cykoi  阅读(89)  评论(0编辑  收藏  举报