[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 }
View Code

 

posted @ 2022-03-12 10:32  PYWBKTDA  阅读(41)  评论(0编辑  收藏  举报