宝桑,您太牛啦!
大家好,我不会根号实锤了。
因为跟众数有关并且看起来就要对所有种类的数求一个答案,可以直接考虑根号算法。
没有什么好的分块思路,不妨根号分治。按数的种类处理,按大小分治:
- 出现次数大于
\sqrt n :这种数最多O(\sqrt n) 个,颜色是O(n) 个的,每种颜色处理一下就是O(n \sqrt n) 的; - 出现次数小于等于
\sqrt n :记其出现位置为p_0=0,p_1,p_2,\cdots ,p_k,p_{k+1}=n+1 ,那么改(p_i, p_j) 对这种数来说最优,枚举i,j ,总时间复杂度分析后可知是O(n \sqrt n) 的。
然后先处理出现次数大于
然后再处理出现次数不大于
那么相当于做
暴力枚举
代码比题解清楚。
void SmChunk()
{
for(int i=1;i<=n;++i) sum[i]=0;
for(int i=1;i<=n;++i)
{
if(app[a[i]]<=Sqr)
{
int p=lower_bound(Pos[a[i]].begin(),Pos[a[i]].end(),i)-Pos[a[i]].begin();
for(int j=p;~j;--j)
{
int l=j?Pos[a[i]][j-1]+1:1,r=Pos[a[i]][j];
maxn[a[i]]=max(maxn[a[i]],sum[l]-(p-j));
while(l<=r && sum[r]<p-j+1) sum[r--]=p-j+1;
}
}
}
}
void Solve()
{
n=read();
for(int i=1;i<=n;++i) a[i]=b[i]=read();
sort(b+1,b+1+n);
len=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+len,a[i])-b;
for(int i=1;i<=len;++i) app[i]=0,Pos[i].clear(),maxn[i]=0;
for(int i=1;i<=n;++i) ++app[a[i]],Pos[a[i]].push_back(i);
for(int p=1;p<=len;++p)
{
if(app[p]>Sqr)
{
for(int i=1;i<=n;++i) sum[i]=sum[i-1]+int(a[i]==p);
for(int q=1;q<=len;++q)
{
int N=app[q],l,s;
l=s=0;
for(int i=0;i<N;++i)
{
int r=Pos[q][i];
s=max(0,s-(sum[r]-sum[l]))+1;
maxn[p]=max(maxn[p],s);
l=r;
}
l=s=0;
for(int i=0;i<N;++i)
{
int r=Pos[q][i];
s=max(0,s)+sum[r]-sum[l];
maxn[q]=max(maxn[q],s--);
l=r;
}
}
}
}
SmChunk();
reverse(a+1,a+1+n);
for(int i=1;i<=len;++i)
{
reverse(Pos[i].begin(),Pos[i].end());
for(auto &st:Pos[i]) st=n-st+1;
}
SmChunk();
for(int i=1;i<=len;++i) maxn[i]+=app[i];
int ans=0;
for(int i=1;i<=len;++i) ans=max(ans,maxn[i]);
write(ans),puts("");
for(int i=1;i<=len;++i) if(maxn[i]==ans) write(b[i]),puts("");
}