而且小的我们可以直接暴力枚举两个分界点(同上面的感觉),但是这样就要快速计算众数。
那我们考虑枚举满足是小的右端点,维护一个数组 Si 表示 i 为左端点的众数。(只需要看小的部分的)
然后考虑怎么更新,就枚举它对应的数,然后考虑这个数是否会作为众数给这个左端点贡献。
但是它也可能给前面的也贡献啊,不过发现前提是这个要贡献,亦或者说这个贡献是一段的,然后我们每个位置都往前尝试贡献,不行就停下来即可。
然后因为我们限制只能小的部分,那 Si 最大也是 √n 级别的,那每次修改至少加一,总共就加 n√n 级别次,所以是没问题的。
然后要稍稍注意的一下就是可能是只有两段(就只有分界点),所以一些地方要记得特判一下之类的。
代码
#include<cstdio>#include<vector>#include<algorithm>usingnamespace std;
constint N = 2e5 + 100;
constint B = 500;
int T, n, a[N], b[N], m, s[N], S[N], id[N], ans[N];
vector <int> pl[N], bg, sm;
voidClear(){
for (int i = 1; i <= m; i++) pl[i].clear(), ans[i] = 0;
for (int i = 1; i <= n; i++) S[i] = 0;
bg.clear(); sm.clear();
}
//x两边 y中间 voidRun1(int x, int y){
int lstv = -1e9, lstp = 0;
for (int i = 0; i < pl[y].size(); i++) { int x = pl[y][i];
lstv = max(lstv, s[x - 1] - i);
lstp = max(lstp, lstv + (i + 1) + (s[n] - s[x]));
}
ans[x] = max(ans[x], lstp);
}
//x中间 y两边 voidRun2(int x, int y){
int lstv = 0, lstp = 0;//lstv=0是开头可以是空的 for (int i = 0; i < pl[y].size(); i++) { int x = pl[y][i];
lstp = max(lstp, lstv + s[x - 1] + (int)pl[y].size() - i);
lstv = max(lstv, i + 1 - s[x]);
}
lstp = max(lstp, lstv + s[n]);//结尾也可以是空的 ans[y] = max(ans[y], lstp);
}
voidwork_big(){
for (int i = 0; i < bg.size(); i++) { int x = bg[i];
for (int j = 1; j <= n; j++) s[j] = s[j - 1] + (a[j] == x);
for (int j = 1; j <= m; j++) if (x != j) Run1(x, j), Run2(x, j);
}
}
voidwork_small(){
for (int i = 1; i <= n; i++) if (pl[a[i]].size() <= B) {//右端点int val = -1e9;
for (int j = -1; j < id[i]; j++) { int x = (j == -1) ? 0 : pl[a[i]][j];//左端点 val = max(val, j + 1 + S[x + 1] + (int)pl[a[i]].size() - id[i]);
}
ans[a[i]] = max(ans[a[i]], val);
//维护 Sfor (int j = id[i]; j >= 0; j--) {
int now = pl[a[i]][j];
while (now && S[now] < id[i] - j + 1)
S[now--] = id[i] - j + 1;
}
}
int val = 0;
for (int i = n; i >= 1; i--) {
ans[a[i]] = max(ans[a[i]], val + id[i] + 1);
val = max(val, (int)pl[a[i]].size() - id[i]);
}
}
voidwrite_ans(){
int big = 0;
for (int i = 1; i <= m; i++) if (ans[i] > big) big = ans[i];
printf("%d\n", big);
for (int i = 1; i <= m; i++) if (ans[i] == big) printf("%d\n", b[i]);
}
intmain(){
// freopen("mode_ex2.in", "r", stdin);// freopen("mode_ex2.out", "w", stdout);scanf("%d", &T);
while (T--) {
scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];
sort(b + 1, b + n + 1); m = unique(b + 1, b + n + 1) - b - 1;
for (int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + m + 1, a[i]) - b, id[i] = pl[a[i]].size(), pl[a[i]].push_back(i);
for (int i = 1; i <= m; i++) if (pl[i].size() >= B) bg.push_back(i); else sm.push_back(i);
work_big();
work_small();
write_ans();
Clear();
}
return0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?