BZOJ2081 : [Poi2010]Beads
暴力枚举$k$,对于一个子串,计算它正着的hash值以及反着的hash值,取最小值得到其最终hash值。
对于$k$,一共有$\lfloor\frac{n}{k}\rfloor$个子串,计算出它们的最终hash值即可统计出不同子串的个数。
时间复杂度$O(n\log n)$。
#include<cstdio> typedef long long ll; const int N=200010,P=2333333,D=1000173169,M=1048575; int n,i,j,pow[N],a[N],pre[N],suf[N],val[N],ans,cnt,now; inline int min(int a,int b){return a<b?a:b;} inline int hash(int l,int r){return min((ll)(pre[r]-(ll)pre[l-1]*pow[r-l+1]%D+D)%D,(ll)(suf[l]-(ll)suf[r+1]*pow[r-l+1]%D+D)%D);} struct E{int v;E*nxt;}*g[M+1],pool[N],*cur=pool,*p; int vis[M+1]; inline bool ins(int v){ int u=v&M; if(vis[u]<i)vis[u]=i,g[u]=NULL; for(p=g[u];p;p=p->nxt)if(p->v==v)return 0; p=cur++;p->v=v;p->nxt=g[u];g[u]=p; return 1; } inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} int main(){ for(read(n),pow[0]=i=1;i<=n;i++)pow[i]=(ll)pow[i-1]*P%D; for(i=1;i<=n;i++)read(a[i]); for(i=1;i<=n;i++)pre[i]=(ll)((ll)pre[i-1]*P+a[i])%D; for(i=n;i;i--)suf[i]=(ll)((ll)suf[i+1]*P+a[i])%D; for(i=1;i<=n;i++)for(cur=pool,j=i;j<=n;j+=i)if(ins(hash(j-i+1,j)))val[i]++; for(i=1;i<=n;i++)if(val[i]>ans)ans=val[i],cnt=1;else if(val[i]==ans)cnt++; for(printf("%d %d\n",ans,cnt),i=1;i<=n;i++)if(val[i]==ans){ if((++now)<cnt)printf("%d ",i); else printf("%d",i); } return 0; }