[cf1446D]Frequency Problem
若原序列众数不唯一,显然答案即为$n$,不妨特判此类情况
结论:记$x$为原序列的众数,则$x$也为答案序列的众数
反证法,假设$x$不是答案序列的众数,则不断延长答案序列直至$x$是其众数
不难发现:这样的时刻必然存在,且此时众数不唯一,即与答案的最长性矛盾
进一步的,对答案序列的众数出现次数分类讨论:
1.若出现次数$\le \sqrt{n}$,枚举出现次数并使用双指针计算即可(贪心选最大的右端点)
2.若众数出现次数$>\sqrt{n}$,根据上述结论,枚举另一个众数$y\ne x$(仅有$o(\sqrt{n})$个)
不妨将$x$和$y$标记为$\pm 1$,其余数标记为$0$,此时所选序列的必要条件即标记和为0
同时,若$x$不为众数则必然不优(与结论证明类似),进而使用前缀和计算即可
时间复杂度为$o(n\sqrt{n})$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 int n,K,x,ans,a[N],cnt[N],Cnt[N],vis[N<<1],sum[N]; 5 int main(){ 6 scanf("%d",&n); 7 for(int i=1;i<=n;i++){ 8 scanf("%d",&a[i]); 9 cnt[a[i]]++; 10 } 11 for(int i=1;i<=n;i++)cnt[0]=max(cnt[0],cnt[i]); 12 for(int i=1;i<=n;i++) 13 if (cnt[i]==cnt[0]){ 14 if (x){ 15 printf("%d\n",n); 16 return 0; 17 } 18 x=i; 19 } 20 K=min((int)sqrt(n),cnt[0]); 21 for(int i=1;i<=K;i++){ 22 memset(Cnt,0,sizeof(Cnt)); 23 for(int j=1,k=1;j<=n;j++){ 24 while ((k<=n)&&(Cnt[a[k]]<i)){ 25 if (++Cnt[a[k]]==i)Cnt[0]++; 26 k++; 27 } 28 if (Cnt[0]>1)ans=max(ans,k-j); 29 if (Cnt[a[j]]--==i)Cnt[0]--; 30 } 31 } 32 for(int i=1;i<=n;i++) 33 if ((i!=x)&&(cnt[i]>K)){ 34 memset(vis,0,sizeof(vis)); 35 for(int j=1;j<=n;j++){ 36 sum[j]=sum[j-1]; 37 if (a[j]==x)sum[j]++; 38 if (a[j]==i)sum[j]--; 39 } 40 for(int j=0;j<=n;j++){ 41 if (!vis[sum[j]+n])vis[sum[j]+n]=j+1; 42 else ans=max(ans,j-vis[sum[j]+n]+1); 43 } 44 } 45 printf("%d\n",ans); 46 return 0; 47 }