题目大意:给定一个字符串S,求一个最长的L(L*2<=n),使S长度为L的前缀和长度为L的后缀循环同构
一开始我的想法是枚举L,判断长度为L的前缀和长度为L的后缀的所有循环同构的哈希值之和是否相等
但是很快我发现这做法是扯淡- - 因为一个字符串所有循环同构的哈希值之和等于这个字符串所有字符ASCII码之和乘上(BASE^len+BASE^(len-1)+...+BASE^2+BASE+1)
然后我在想能不能考虑修改一下哈希函数呢?
比如给每个字符一个BASE,定义一个字符串的哈希值为以字符串开头字符的BASE值为进制的RK哈希……
结果下来数据发现卡自然溢出哈希的那个abbabaab对我的算法效果良好- -
尼玛连abbabacbaabab这种简单的字符串都能卡掉我的代码QAQ
最后…… 膜拜题解…… http://blog.csdn.net/zeyu_king/article/details/42521093
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 1001001 #define BASE 131 #define MOD 45119 using namespace std; int n,ans,f[M>>1]; char s[M]; int hash[M],power[M]; int Get_Hash(int l,int r) { int len=r-l+1; return (hash[r]-hash[l-1]*power[len]%MOD+MOD)%MOD; } int main() { int i; cin>>n; scanf("%s",s+1); for(power[0]=1,i=1;i<=n;i++) { hash[i]=(hash[i-1]*BASE+s[i])%MOD; power[i]=power[i-1]*BASE%MOD; } for(i=n>>1;i;i--) { f[i]=min(f[i+1]+2,(n>>1)-i+1); while( f[i]>0 && Get_Hash(i,i+f[i]-1) != Get_Hash(n-i+1-f[i]+1,n-i+1) ) f[i]--; } for(i=1;i<=n>>1;i++) if( Get_Hash(1,i-1) == Get_Hash(n-i+2,n) ) ans=max(ans,i+f[i]-1); cout<<ans<<endl; return 0; }
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 1001001 using namespace std; typedef unsigned long long ll; const ll bases[26]={31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151}; int n,ans; char s[M]; ll l1[26],l2[26],r1[26],r2[26],lsum[26],rsum[26],lbases[26],rbases[26]; ll Quick_Power(ll x,int y) { ll re=1; while(y) { if(y&1) re*=x; x*=x; y>>=1; } return re; } int main() { int i,j; cin>>n; scanf("%s",s+1); for(i=1;i<=n>>1;i++) { int x1=s[i]-'a'; int x2=s[n-i+1]-'a'; if(i!=1) { int y2=s[n-i+2]-'a'; r1[y2]-=rsum[y2]; r1[x2]+=rsum[x2]; rbases[y2]-=Quick_Power(bases[y2],i-2); rbases[x2]+=Quick_Power(bases[x2],i-2); } bool flag=true; for(j=0;j<26;j++) { if(j==x1) lbases[j]+=Quick_Power(bases[j],i-1); (rbases[j]*=bases[j])+=(j==s[n-i+1+(i!=1)]-'a'); (l1[j]*=bases[j])+=x1*lbases[j]; r1[j]+=x2*rbases[j]; if(l1[j]+l2[j]!=r1[j]+r2[j]) flag=false; } if(flag) ans=i; for(j=0;j<26;j++) { (lsum[j]*=bases[j])+=x1; rsum[j]+=x2*Quick_Power(bases[j],i-1); if(j==s[i+1]-'a') l2[j]+=lsum[j]; (r2[j]+=(j==s[n-i+1]-'a')?rsum[j]:0)*=bases[j]; } } cout<<ans<<endl; return 0; }
BZOJ 2803 Poi2012 Prefixuffix Hash
原文地址:http://blog.csdn.net/popoqqq/article/details/44058857