• [ZJOI 2022] 众数


    \(\mathbb{D}\rm escription\)

    \(\mathcal{P}\text{ortal.}\)

    \(\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\),可以得到

    \[\text{Ans}_y=\max_{0\le j<i}\{\text{pre}_j-s_j\}+s_i+\text{suf}_{i+1} \]

    其中取 \(\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;
    }
    
  • 相关阅读:
    【2017.12.02普及组模拟】送快递
    【NOIP2013模拟联考7】OSU
    顺序表元素位置倒置示例c++实现
    c++字符串排序
    JAVA实现四则运算的简单计算器
    JAVA图形小动画之简单行星运动
    JAVA多线程编程
    ege图形库之简单贪吃蛇(c++)
    ege图形库之动画排序
    c语言中一种典型的排列组合算法
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/16277835.html
Copyright © 2020-2023  润新知