传送门
世纪水题???(大雾
题意:
给定一个串。你可以把这个串分成若干段,每块都有k个字符。(如果最后一段字符数少于k,则丢掉不要)
对于不同的k,你能得到不同的段。两个段是本质相同的,当且仅当它们相等或将其中一个段翻转后它们相等。
你现在想知道:能够获得的最多的本质不同段数;能获得这个最大值的k的数目;能获得这个最大值的所有k。
思路:
暴力枚举段的长度,然后用
h
a
s
h
+
s
e
t
hash+set
hash+set统计答案。
根据调和级数的性质复杂度是两只
l
o
g
log
log的。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=2e5+5;
typedef long long ll;
typedef unsigned long long Ull;
typedef pair<Ull,int> pii;
const Ull bas=311;
set<Ull>S;
int n,a[N];
struct string_hash{
Ull pw1[N],s1[N];
inline void init(){
pw1[0]=1;
for(ri i=1;i<=n;++i)pw1[i]=pw1[i-1]*bas;
for(ri i=1;i<=n;++i)s1[i]=s1[i-1]*bas+(Ull)a[i];
}
inline Ull get1(int l,int r){return s1[r]-s1[l-1]*pw1[r-l+1];}
}S1,S2;
int main(){
n=read();
for(ri i=1;i<=n;++i)a[i]=read();
S1.init();
reverse(a+1,a+n+1);
S2.init();
reverse(a+1,a+n+1);
int ans=0;
vector<int>Ans;
for(ri cnt=0,len=1;len<=n;++len,cnt=0){
S.clear();
for(ri l=1,r=len;l<=n&&r<=n;l+=len,r+=len){
if(!S.count(S1.get1(l,r)*S2.get1(n-r+1,n-l+1))){
++cnt;
S.insert(S1.get1(l,r)*S2.get1(n-r+1,n-l+1));
}
}
if(cnt>ans)Ans.clear(),ans=cnt;
if(cnt==ans)Ans.push_back(len);
}
cout<<ans<<' '<<Ans.size()<<'\n';
for(ri i=0;i<Ans.size();++i)cout<<Ans[i]<<' ';
return 0;
}