正反各做一遍哈希来判断,然后在两个哈希值里取一个$max/min$做哈希值,然后每次把子串们的哈希插进$set$里,最后统计集合大小,就可以优秀地在$O(nlog^2$ $n)$中出解了
然后我觉得这样太没有理想了,就写了一个挂链哈希表,结果跑的贼慢。。。
我挂链时的区分方法是换模数再模出一个新值,然后这样做的时候注意要和哈希表的基数和模数区分开
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=200050,M=2500; 6 const long long bs=1009,md=2333; 7 const long long bas=203339,mod=2147483647; 8 long long num[N],hah[N][2],huh[N][2],pw[N][2],val[N]; 9 int p[M],nxt[N],outp[N]; 10 int n,pos,cnt,ans; 11 long long Ghash(int l,int r,int t) 12 { 13 long long mdd=t?mod:md; 14 long long h1=((hah[r][t]-hah[l-1][t]*pw[r-l+1][t])%mdd+mdd)%mdd; 15 long long h2=((huh[l][t]-huh[r+1][t]*pw[r-l+1][t])%mdd+mdd)%mdd; 16 return max(h1,h2); 17 } 18 bool Fhash(long long has,long long hsh) 19 { 20 for(int i=p[has%md];i;i=nxt[i]) 21 if(val[i]==hsh) return true; 22 return false; 23 } 24 void Ihash(long long has,long long hsh) 25 { 26 if(Fhash(has,hsh)) return ; 27 nxt[++cnt]=p[pos=has%md]; 28 val[cnt]=hsh,p[pos]=cnt; 29 } 30 int main () 31 { 32 scanf("%d",&n),pw[0][0]=pw[0][1]=1; 33 for(int i=1;i<=n;i++) 34 { 35 scanf("%lld",&num[i]); 36 pw[i][0]=pw[i-1][0]*bs%md; 37 pw[i][1]=pw[i-1][1]*bas%mod; 38 } 39 for(int i=1;i<=n;i++) 40 { 41 hah[i][0]=(hah[i-1][0]*bs+num[i])%md; 42 hah[i][1]=(hah[i-1][1]*bas+num[i])%mod; 43 } 44 for(int i=n;i;i--) 45 { 46 huh[i][0]=(huh[i+1][0]*bs+num[i])%md; 47 huh[i][1]=(huh[i+1][1]*bas+num[i])%mod; 48 } 49 for(int i=1;i<=n;i++) 50 { 51 memset(p,0,sizeof p); cnt=0; 52 for(int j=1;j<=n-i+1;j+=i) 53 Ihash(Ghash(j,j+i-1,0),Ghash(j,j+i-1,1)); 54 if(cnt>ans) ans=cnt,outp[outp[0]=1]=i; 55 else if(cnt==ans) outp[++outp[0]]=i; 56 } 57 printf("%d %d ",ans,outp[0]); 58 for(int i=1;i<=outp[0];i++) 59 printf("%d ",outp[i]); 60 return 0; 61 }