\(\mathbb{D}\rm escription\)
\(\mathbb{S}\rm olution\)
首先有一个 \(\rm observation\):最终答案一定是以区间 \([l,r]\) 为划分,选取 \([l,r]\) 内的众数变成 \([l,r]\) 外的众数。
由 "\(a_i\) 只有 \(5\) 种取值" 的部分分启发,我们可以想到枚举从颜色 \(x\) 转移到颜色 \(y\),再 \(\mathcal O(n)\) 地进行计算,总共是 \(\mathcal O(c^2n)\) 的。具体而言,记 \(\text{pre}_i,\text{suf}_i\) 分别为颜色 \(y\) 出现次数的前/后缀和,\(s_i\) 为颜色 \(x\) 的前缀和,我们从左到右枚举 \(r=i\),可以得到
其中取 \(\max\) 的 \(j+1\) 就是我们的 \(l\).
考场上我做到这里就捡 \(40\text{ pts}\) 跑路了。不过这个算法有没有优化的空间呢?事实上 \(\mathcal O(n)\) 计算是不必要的,我们只需要枚举颜色为 \(y\) 的下标即可!也就是说,如果枚举颜色 \(x\),我们可以 \(\mathcal O(n)\) 地计算它转移到其它所有颜色的贡献!可以想到,如果枚举出现次数大于 \(B\) 的颜色 \(x\),复杂度就会变得正常,也就是 \(\mathcal O(n^2/B)\).
如果解决出现次数小于 \(B\) 的颜色 \(x\) 转移到出现次数小于 \(B\) 的颜色 \(y\),这个问题就解决了。
还是尝试分块。连续的区间要好做一些,所以枚举出现次数小于 \(B\) 的颜色 \(x\) 的出现次数 \(k\)(注意这里是先枚举出现次数),预处理 \(\text{pre}_i\) 表示位置 \(i\) 的颜色往前第 \(k\) 个同颜色的下标,再对 \(\text{pre}_i\) 做一个前缀 \(\max\) 以方便后文的计算。枚举颜色 \(y\),还是类似上文的优化思想,只枚举颜色为 \(y\) 的下标 \(i\),取 \(j=\text{pre}_{i-1}\) 就可以保证 \([j,i)\) 恰好存在能向 \(y\) 转移的颜色 \(x\),且留下的颜色 \(y\) 个数最大。复杂度 \(\mathcal O(nB)\).
\(B\) 取 \(\sqrt n\) 即可得到 \(\mathcal O(n\sqrt n)\) 的复杂度。
$\mathbb{C}\rm ode $
竟然一发写过,我真的泪目了。
# include <cstdio>
# include <cctype>
# define print(x,y) write(x), putchar(y)
template <class T>
inline T read(const T sample) {
T x=0; char s; bool f=0;
while(!isdigit(s=getchar())) f|=(s=='-');
for(; isdigit(s); s=getchar()) x=(x<<1)+(x<<3)+(s^48);
return f? -x: x;
}
template <class T>
inline void write(T x) {
static int writ[50], w_tp=0;
if(x<0) putchar('-'), x=-x;
do writ[++w_tp]=x-x/10*10, x/=10; while(x);
while(putchar(writ[w_tp--]^48), w_tp);
}
# include <cmath>
# include <vector>
# include <iostream>
# include <algorithm>
using namespace std;
const int maxn = 2e5+5;
vector <int> ele[maxn];
int len,B,s[maxn],ans[maxn],Ans,pre[maxn];
int n,a[maxn],b[maxn],cnt[maxn],rk[maxn];
inline void handle_big() {
for(int x=1;x<=len;++x) {
if(cnt[x]<=B) continue;
for(int i=1;i<=n;++i)
s[i] = s[i-1]+(a[i]==x);
for(int y=1;y<=len;++y) if(x^y) {
int premax=0;
for(const auto& i:ele[y]) {
ans[y] = max(ans[y],premax+s[i-1]+cnt[y]-rk[i]+1);
premax = max(premax,rk[i]-s[i]);
}
Ans = max(Ans,ans[y]);
}
}
}
inline void handle_small() {
int upper=0;
for(int i=1;i<=len;++i) {
ele[i].emplace_back(n+1);
if(cnt[i]<=B) upper=max(upper,cnt[i]);
}
for(int k=1;k<=upper;++k) {
for(int i=1;i<=n;++i)
if(rk[i]<k) pre[i]=-1;
else pre[i] = ele[a[i]][rk[i]-k];
for(int i=2;i<=n;++i)
pre[i] = max(pre[i-1],pre[i]);
for(int y=1;y<=len;++y) {
int pos=-1;
for(const auto& i:ele[y]) {
int j = pre[i-1];
if(j==-1) continue;
while(ele[y][pos+1]<j) ++pos;
if(i==n+1) ans[y] = max(ans[y],k+pos+1);
else ans[y] = max(ans[y],k+cnt[y]-(rk[i]-pos-2));
}
Ans = max(Ans,ans[y]);
}
}
}
inline void CandyIsMyWife() {
n=read(9); B=sqrt(n); Ans=0;
for(int i=1;i<=n;++i) {
ans[i]=cnt[i]=0; ele[i].clear();
a[i]=b[i]=read(9);
}
sort(b+1,b+n+1), len=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;++i) {
a[i] = lower_bound(b+1,b+len+1,a[i])-b;
rk[i] = ++ cnt[a[i]];
ele[a[i]].emplace_back(i);
}
handle_big();
handle_small();
print(Ans,'\n');
for(int i=1;i<=len;++i)
if(Ans==ans[i]) print(b[i],'\n');
}
int main() {
freopen("mode.in","r",stdin);
freopen("mode.out","w",stdout);
pre[0]=-1;
for(int T=read(9); T; --T) CandyIsMyWife();
return 0;
}