题意
Zxl有一次决定制造一条项链,她以非常便宜的价格买了一长条鲜艳的珊瑚珠子,她现在也有一个机器,能把这条珠子切成很多块(子串),每块有k(k>0)个珠子,如果这条珠子的长度不是k的倍数,最后一块小于k的就不要拉(nc真浪费),保证珠子的长度为正整数。 Zxl喜欢多样的项链,为她应该怎样选择数字k来尽可能得到更多的不同的子串感到好奇,子串都是可以反转的,换句话说,子串(1,2,3)和(3,2,1)是一样的。写一个程序,为Zxl决定最适合的k从而获得最多不同的子串。 例如:这一串珠子是: (1,1,1,2,2,2,3,3,3,1,2,3,3,1,2,2,1,3,3,2,1), k=1的时候,我们得到3个不同的子串: (1),(2),(3) k=2的时候,我们得到6个不同的子串: (1,1),(1,2),(2,2),(3,3),(3,1),(2,3) k=3的时候,我们得到5个不同的子串: (1,1,1),(2,2,2),(3,3,3),(1,2,3),(3,1,2) k=4的时候,我们得到5个不同的子串: (1,1,1,2),(2,2,3,3),(3,1,2,3),(3,1,2,2),(1,3,3,2)
n<=200000,a[i]<=n
分析
若我们暴力枚举所有子串的话,复杂度为
n1+n2+...+nn=n(ln(n)+c)
c为欧拉常数,貌似约等于0.5,所以说这个复杂度是可以过的。
那么我们双哈希暴力枚举即可。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define LL long long
using namespace std;
const int N=200005;
const LL MOD1=5971849;
const LL MOD2=1000037;
int n,cnt,sum,a[N];
LL last[MOD1],hash1[N],hash2[N],mi1[N],mi2[N],Hash1[N],Hash2[N];
struct edge{LL y;int next;}e[N*40];
vector<int> ans;
vector<LL> w;
void addedge(LL x,LL y,LL X,LL Y)
{
int flag=0;
for (int i=last[x];i;i=e[i].next)
if (e[i].y==y)
{
flag=1;break;
}
if (!flag)
{
sum++;
if (!last[x]) w.push_back(x);
e[++cnt].y=y;e[cnt].next=last[x];last[x]=cnt;
if (!last[X]) w.push_back(X);
e[++cnt].y=Y;e[cnt].next=last[X];last[X]=cnt;
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
mi1[0]=mi2[0]=1;
for (int i=1;i<=n;i++) mi1[i]=(LL)mi1[i-1]*(n+1)%MOD1,mi2[i]=(LL)mi2[i-1]*(n+1)%MOD2;
for (int i=1;i<=n;i++)
{
hash1[i]=((LL)hash1[i-1]*(n+1)+a[i])%MOD1;
hash2[i]=((LL)hash2[i-1]*(n+1)+a[i])%MOD2;
}
for (int i=n;i>=1;i--)
{
Hash1[i]=((LL)Hash1[i+1]*(n+1)+a[i])%MOD1;
Hash2[i]=((LL)Hash2[i+1]*(n+1)+a[i])%MOD2;
}
int mx=0,tot=0;
for (int i=1;i<=n;i++)
{
sum=0;
for (int j=1;j<=n&&j+i-1<=n;j+=i)
{
LL x=(hash1[j+i-1]-hash1[j-1]*mi1[i]%MOD1+MOD1)%MOD1,y=(hash2[j+i-1]-hash2[j-1]*mi2[i]%MOD2+MOD2)%MOD2;
LL X=(Hash1[j]-Hash1[j+i]*mi1[i]%MOD1+MOD1)%MOD1,Y=(Hash2[j]-Hash2[j+i]*mi2[i]%MOD2+MOD2)%MOD2;
addedge(x,y,X,Y);
}
if (sum>mx)
{
mx=sum;tot=1;
ans.clear();ans.push_back(i);
}
else if (sum==mx)
{
tot++;ans.push_back(i);
}
cnt=0;
for (vector<LL>::iterator it=w.begin();it!=w.end();it++) last[*it]=0;
w.clear();
}
sort(ans.begin(),ans.end());
printf("%d %d\n",mx,tot);
for (int i=0;i<tot-1;i++) printf("%d ",ans[i]);
printf("%d",ans[tot-1]);
return 0;
}