题解 P3498 【[POI2010]KOR-Beads】
题目大意:
给出
思路:
本题朴素的思路是枚举
枚举
展开后得到
近似于
把
我们可以发现
又因为我们的比较和记录的时间复杂度是
所以我们便可以想到使用哈希。
与一般的哈希一样,我们先从头弄一个前缀哈希和幂数组,这样若要求
那么我们的哈希怎么判重呢?我们可以用除余法,若冲突则在下一位保存。如果我们在判重时正反顺序两个都不冲突,我们才认为它是新串,并将正反顺序的哈希值保存下来。
但是我们这里每枚举一次
其他记录答案什么的就是朴素的暴力做法啦~
代码:
#include<cstdio>//以下为了防止不必要的错误,类型我全都开成了unsigned long long
unsigned long long n,m,i,j1,j2,k,max,nans,ans[200005],a[200005],hash[1000007],b[1000007],power[200005],ha1[200005],ha2[200005];//此处的hash为判重数组,b为time数组,power为幂数组,ha1为前缀哈希,ha2为后缀哈希
unsigned long long ha(unsigned long long x)//判重
{
unsigned long long y=x%1000007;
if (b[y]==m&&hash[y]!=x)
{
y++;
if (y==n/m)
y=0;
}
return y;
}
int main()
{
scanf("%d",&n);
power[0]=1;
for (m=1;m<=n;m++)
scanf("%d",&a[m]),power[m]=power[m-1]*19260817,ha1[m]=ha1[m-1]*19260817+a[m];//读入并预处理幂数组与前缀哈希
for (m=n;m;m--)
ha2[m]=ha2[m+1]*19260817+a[m];//预处理后缀哈希
for (m=1;m<=n;m++)//枚举题目中的k
{
k=0;//k为不同串的个数
for (i=m+1;i<=n+1;i+=m)
{
j1=ha(ha1[i-1]-ha1[i-m-1]*power[m]);
if (hash[j1]==ha1[i-1]-ha1[i-m-1]*power[m])//判断正序是否重复
continue;
j2=ha(ha2[i-m]-ha2[i]*power[m]);
if (hash[j2]==ha2[i-m]-ha2[i]*power[m])//判断反序是否重复
continue;
b[j1]=b[j2]=m,hash[j1]=ha1[i-1]-ha1[i-m-1]*power[m],hash[j2]=ha2[i-m]-ha2[i]*power[m],k++;//记录时间戳,保存正反顺序两个串
}
//以下为记录答案
if (k>max)
max=k,nans=1,ans[1]=m;
else
if (k==max)
nans++,ans[nans]=m;
}
printf("%lld %lld\n",max,nans);
for (m=1;m<=nans;m++)
printf("%lld ",ans[m]);
return 0;
}