P8330-[ZJOI2022]众数【根号分治】

正题

题目链接:https://www.luogu.com.cn/problem/P8330


题目大意

给出一个长度为n的序列a,你可以选择其中一个区间将其加上任意整数,要求这个序列的众数出现次数最多。

输出最多次数和可能的众数。

1n2×105,1ai109,n5×105,保证不所有数都相等。


解题思路

相当于找到一个区间使得区间外和区间内的众数次数和最大。

这个和出现次数挂钩,考虑根号分治。对于出现次数大于n的数字,这种数字不会超过n个,可以考虑对每个数字暴力做。

假设在区间外的数字是x,区间内的是y,那么我们区间中每个x会令答案1,每个y会令答案+1。将x的位置视为1y的位置视为1,那么最大答案就是x的出现次数加最大子段和。

这个复杂度可以做到min(cx,cy),其中cx表示x的出现次数。

那对于每个cx>n的我们都可以O(n)解决它在外或者在内的情况。

然后考虑cxncyn的情况,先把所有cx>nx给去掉,此时注意到任何区间的众数个数都是n的,那么我们预处理出fl,i表示一个最小的r,满足[l,r]的众数出现次数为i,这样我们对于每个在外面的x枚举两个x的位置作为端点,然后单指针移动计算他们之间区间的众数出现次数即可。

时间复杂度:O(nn)


解题思路

#include<cstdio> #include<cstring> #include<algorithm> #include<cctype> #include<vector> #include<cmath> using namespace std; const int N=2e5+10,M=450; int n,T,a[N],b[N],r[N][M],s[N]; vector<int> v[N],pr[N]; int read(){ int x=0,f=1;char c=getchar(); while(!isdigit(c)){if(c=='-')f=-f;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();} return x*f; } void calc(int x,int y){ int ans1=0,ans2=0,now1=0,now2=0,las=0; for(int i=0;i<v[y].size();i++){ now1=max(now1+s[v[y][i]]-s[las],0); ans1=max(ans1,now1);now1=max(now1-1,0); now2=max(now2-s[v[y][i]]+s[las],1); ans2=max(ans2,now2); las=v[y][i]; } pr[ans1+v[y].size()].push_back(y); pr[ans2+v[x].size()].push_back(x); return; } int main() { // freopen("mode_ex2.in","r",stdin); int cas=read(); while(cas--){ n=read();T=445; for(int i=1;i<=n;i++)pr[i].clear(),v[i].clear(); for(int i=1;i<=n+1;i++) for(int j=0;j<T;j++)r[i][j]=n+1; for(int i=1;i<=n;i++)a[i]=read(),b[i]=a[i]; sort(b+1,b+1+n); int m=unique(b+1,b+1+n)-b-1; for(int i=1;i<=n;i++){ a[i]=lower_bound(b+1,b+1+m,a[i])-b; v[a[i]].push_back(i); } for(int x=1;x<=m;x++){ pr[v[x].size()].push_back(x); if(v[x].size()>T){ for(int i=1;i<=n;i++)s[i]=0; for(int i=0;i<v[x].size();i++)s[v[x][i]]++; for(int i=1;i<=n;i++)s[i]+=s[i-1]; for(int i=1;i<=m;i++) if(i!=x)calc(x,i); } } for(int x=1;x<=m;x++){ if(v[x].size()<=T){ for(int i=0;i<v[x].size();i++) for(int j=i;j<v[x].size();j++) r[v[x][i]][j-i]=v[x][j]; } } for(int i=n;i>=1;i--) for(int j=0;j<T;j++) r[i][j]=min(r[i][j],r[i+1][j]); for(int x=1;x<=m;x++){ if(v[x].size()<=T){ for(int i=-1;i<(int)v[x].size();i++){ int l=(i==-1)?0:v[x][i];l++; for(int j=0,z=i+1;j<T;j++){ if(r[l][j]>n)break; while(z<v[x].size()&&v[x][z]<=r[l][j])z++; pr[v[x].size()+j+1-(z-i-1)].push_back(x); } } } } int ans=0; for(int i=n;i>=1;i--) if(pr[i].size()){ans=i;break;} printf("%d\n",ans); sort(pr[ans].begin(),pr[ans].end()); printf("%d\n",b[pr[ans][0]]); for(int i=1;i<pr[ans].size();i++) if(pr[ans][i-1]!=pr[ans][i]) printf("%d\n",b[pr[ans][i]]); } return 0; }
posted @   QuantAsk  阅读(72)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤
点击右上角即可分享
微信分享提示