BZOJ2081 : [Poi2010]Beads

暴力枚举$k$,对于一个子串,计算它正着的hash值以及反着的hash值,取最小值得到其最终hash值。

对于$k$,一共有$lfloorfrac{n}{k} floor$个子串,计算出它们的最终hash值即可统计出不同子串的个数。

时间复杂度$O(nlog 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
",ans,cnt),i=1;i<=n;i++)if(val[i]==ans){
    if((++now)<cnt)printf("%d ",i);
    else printf("%d",i);
  }
  return 0;
}

  

原文地址:https://www.cnblogs.com/clrs97/p/4703580.html