版权声明:未经本蒟蒻同意,请勿转载本蒻博客 https://blog.csdn.net/wddwjlss/article/details/83118068
题意: 给出 个数,可将它们分为连续的若干个串,每个串有 个数(长度不足 则丢弃),如串 ,当 时,我们得到 个不同的子串: 。 求使得不同的串最多的 值及串的个数。串可翻转,即子串 和 被认为是一样的。
我们预处理出前缀哈希和后缀哈希,这里我们自然溢出,对于枚举到的每一个k,我们求出每一段的前缀哈希和后缀哈希,然后将2者相乘用set判重。
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int c=2000001001;
int n,a[1001000],k;
ull hash1[1001000],mi[1001000],ans,res[1001000],maxn,hash2[1001000];
set<ull> s;
int main()
{
mi[0]=1;
cin>>n;
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
for(int i=1;i<=n;++i)
{
hash1[i]=hash1[i-1]*c+a[i];//前缀哈希
mi[i]=mi[i-1]*c;
}
for(int i=n;i>=1;--i)
hash2[i]=hash2[i+1]*c+a[i];//后缀哈希
for(int i=1;i<=n;++i)//枚举题目中的k
{
if(n/i<maxn)//对于当前的k如果可以分成的段数小于已经求出的最大值
break;
s.clear();
k=0;
for(int j=i;j<=n;j+=i)//枚举每一段
{
ull g1=hash1[j]-hash1[j-i]*mi[i];//这一段的前缀哈希
ull g2=hash2[j-i+1]-hash2[j+1]*mi[i];//这一段的后缀哈希
ull g3=g1*g2;//将2者相乘放入set里
if(s.count(g3))
continue;
s.insert(g3);
k++;
}
if(k>maxn)
{
ans=1;
maxn=k;
res[ans]=i;
}
else if(k==maxn)
{
ans++;
res[ans]=i;
}
}
cout<<maxn<<" "<<ans<<endl;
for(int i=1;i<=ans;++i)
printf("%d ",res[i]);
return 0;
}