分析
找不同的子串->字符串Hash
这里因为子串可以反转,所以前缀后缀Hash值。
在找是否重复时不能直接用循环,会超时。
有2种方法:set和Hash表。
因为set是STL中的函数,所以我用的是Hash表来实现。
这里要注意一点,在初始化Hash表时不用memset,只需要初始化上次用过的即可。(详见代码)
输出k用vector统计。
代码
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define full(a,b) memset(a,b,sizeof a)
#define ll long long
#define ull unsigned ll
int read()//快读
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x*f;
}
#define debug 1
#define N 200005
#define b 13131
#define H 999979 //用一个较大的质数当下标
int n,arr[N],cnt,mx;
ull f[N],g[N],p[N];
int head[H],nxt[H],ecnt;
ull to[H];
int csh[N],sum;//用来统计上次用的Hash表下标
vector<int> v;
ull hh(int S,int E,int flag)//求字符串的区间Hash值
{
if(!flag) return f[E]-f[S-1]*p[E-S+1];
return g[S]-g[E+1]*p[E-S+1];
}
void add(int h,ull u)//增加一个结点
{
to[++ecnt]=u;
nxt[ecnt]=head[h];
head[h]=ecnt;
csh[++sum]=h;
}
int F(ull key)//Hash函数
{
return key%H;
}
int query(ull x)//询问
{
int h=F(x);
for(int i=head[h]; i!=-1; i=nxt[i])
if(to[i]==x) return 1;
return 0;
}
int main()
{
if(debug==-1)
{
freopen("Beads.in","r",stdin);
freopen("Beads.out","w",stdout);
}
p[0]=1;
for(int i=1; i<N; i++)
p[i]=p[i-1]*b;//初始化
n=read();
for(int i=1; i<=n; i++)
arr[i]=read();
f[1]=arr[1];
for(int i=2; i<=n; i++)
f[i]=f[i-1]*b+arr[i];
g[n]=arr[n];
for(int i=n-1; i>=1; i--)
g[i]=g[i+1]*b+arr[i];//前缀后缀
full(head,-1);
for(int k=1; k<=n; k++)
{
cnt=ecnt=0;
for(int i=1; i<=sum; i++)
head[csh[i]]=-1;//只初始化上次用了的
sum=0;
for(int i=1; i+k-1<=n; i+=k)
{
ull t1=hh(i,i+k-1,0),t2=hh(i,i+k-1,1);
if(query(t1)) continue;
add(F(t1),t1);add(F(t2),t2);//插入前缀,后缀Hash值
++cnt;
}
if(cnt>mx) //有比原来更大的答案
{
mx=cnt;//更新最大值
v.clear();
v.push_back(k);
}
else if(cnt==mx) v.push_back(k);//是最大值,插入k
}
printf("%d %d\n",mx,v.size());
for(int i=0,sz=v.size(); i<sz; i++)
printf("%d ",v[i]);
return 0;
}