zoukankan      html  css  js  c++  java
  • CH4401 蒲公英

    题意

    描述

    题目PDF

    样例输入

    6 3
    1 2 3 2 1 2
    1 5
    3 6
    1 5

    样例输出

    1
    2
    1

    来源

    石家庄二中Violet 6杯省选模拟赛

            </article>
    

    分析

    分块。
    分成长度为T的tot块。因为众数只可能是整块里的众数或者是在整块外面又出现的数,所以可以预处理出任意连续的几块中每个数出现的的次数【需要离散化】和众数,再对询问区间中不在整块里的暴力统计,总复杂度O(n * tot^2+m * T),其中tot * T=n。取tot=n^(1/3),T=n^(2/3)。
    时间复杂度O(n^(5/3)),空间复杂度O(n^(5/3))。

    代码

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;rg char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
        while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
        return data*w;
    }
    template<class T>il T read(rg T&x) {return x=read<T>();}
    typedef long long ll;
    using namespace std;
    
    co int N=4e4+6,T=37;
    int a[N],b[N],L[N],R[N],pos[N],c[T][T][N],f[T][T][2],now[2];
    void work(int x,int y,int num){
    	++c[x][y][num];
    	if(c[x][y][num]>now[0]||c[x][y][num]==now[0]&&num<now[1])
    		now[0]=c[x][y][num],now[1]=num;
    }
    int ask(int l,int r){
    	int p=pos[l],q=pos[r];
    	int x=0,y=0;
    	if(p+1<=q-1) x=p+1,y=q-1;
    	copy(f[x][y],f[x][y]+2,now);
    	if(p==q){
    		for(int i=l;i<=r;++i) work(x,y,a[i]);
    		for(int i=l;i<=r;++i) --c[x][y][a[i]];
    	}
    	else{
    		for(int i=l;i<=R[p];++i) work(x,y,a[i]);
    		for(int i=L[q];i<=r;++i) work(x,y,a[i]);
    		for(int i=l;i<=R[p];++i) --c[x][y][a[i]];
    		for(int i=L[q];i<=r;++i) --c[x][y][a[i]];
    	}
    	return b[now[1]];
    }
    int main(){
    //	freopen(".in","r",stdin),freopen(".out","w",stdout);
    	int n=read<int>(),m=read<int>();
    	for(int i=1;i<=n;++i) b[i]=read(a[i]);
    	sort(b+1,b+n+1);
    	int tot=unique(b+1,b+n+1)-(b+1);
    	for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
    	int t=pow(n,1.0/3);
    	int len=t?n/t:n;
    	for(int i=1;i<=t;++i) L[i]=(i-1)*len+1,R[i]=i*len;
    	if(R[t]<n) L[t+1]=R[t]+1,R[++t]=n;
    	for(int i=1;i<=t;++i)for(int j=L[i];j<=R[i];++j) pos[j]=i;
    	for(int i=1;i<=t;++i)for(int j=1;j<=t;++j){
    		for(int k=L[i];k<=R[j];++k) ++c[i][j][a[k]];
    		for(int k=1;k<=tot;++k) if(c[i][j][k]>f[i][j][0])
    			f[i][j][0]=c[i][j][k],f[i][j][1]=k;
    	}
    	for(int x=0,l,r;m--;){
    		l=(read<int>()+x-1)%n+1,r=(read<int>()+x-1)%n+1;
    		if(l>r) swap(l,r);
    		printf("%d
    ",x=ask(l,r));
    	}
    	return 0;
    }
    

    再分析

    在线区间众数的分块做法比较多,这里提供一个思路:

    首先离散化一下比较方便。

    最初可能会有一个想法,是不是众数只可能是完整的块的众数,或者不完整的块出现的数呢?显然很容易得出反例。

    应该是完整的所有块的众数,和不完整块中出现的数。

    所以我们可以预处理f(i,j)表示第 i 块到第 j 块的众数(枚举 i 开个桶扫一遍)。

    那么只要能快速得出一个数在某个区间内出现次数即可,每次只要比较至多2√n+1个元素的出现次数,这题就解决了。

    由于没有修改,只要离散化以后,给每个数 x 开个vector,按顺序存下 x 出现的位置,每次询问 x 时把区间的左右端点放进对应 vector 二分一下即可。

    根据均值不等式,可以算出分块大小大概是√(n/logn)

    再代码

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;rg char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
        while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
        return data*w;
    }
    template<class T>il T read(rg T&x) {return x=read<T>();}
    typedef long long ll;
    using namespace std;
    
    co int N=4e4+6,T=806;
    int a[N],b[N],c[N],L[N],R[N],pos[N],f[T][T];
    vector<int> e[N];
    int find(int x,int l,int r) {return upper_bound(e[x].begin(),e[x].end(),r)-lower_bound(e[x].begin(),e[x].end(),l);}
    void work(int x,int l,int r,int&ans,int&cnt){
    	int w=find(x,l,r);
    	if(w>cnt||w==cnt&&x<ans) cnt=w,ans=x;
    }
    int ask(int l,int r){
    	int p=pos[l],q=pos[r];
    	int ans=0,cnt=0;
    	if(p==q){
    		for(int i=l;i<=r;++i) work(a[i],l,r,ans,cnt);
    		return b[ans];
    	}
    	int x=0,y=0;
    	if(p+1<=q-1) x=p+1,y=q-1;
    	for(int i=l;i<=R[p];++i) work(a[i],l,r,ans,cnt);
    	for(int i=L[q];i<=r;++i) work(a[i],l,r,ans,cnt);
    	if(f[x][y]) work(f[x][y],l,r,ans,cnt);
    	return b[ans];
    }
    int main(){
    //	freopen(".in","r",stdin),freopen(".out","w",stdout);
    	int n=read<int>(),m=read<int>();
    	for(int i=1;i<=n;++i) b[i]=read(a[i]);
    	sort(b+1,b+n+1);
    	int tot=unique(b+1,b+n+1)-b-1;
    	for(int i=1;i<=n;++i) e[a[i]=lower_bound(b+1,b+tot+1,a[i])-b].push_back(i);
    	int t=sqrt(n*log(n)/log(2));
    	int len=t?n/t:n;
    	for(int i=1;i<=t;++i) L[i]=(i-1)*len+1,R[i]=i*len;
    	if(R[t]<n) L[t+1]=R[t]+1,R[++t]=n;
    	for(int i=1;i<=t;++i)for(int j=L[i];j<=R[i];++j) pos[j]=i;
    	for(int i=1;i<=t;++i){
    		fill(c+1,c+tot+1,0);
    		int cnt=0,ans=0;
    		for(int j=L[i];j<=n;++j){
    			if(++c[a[j]]>cnt||c[a[j]]==cnt&&a[j]<ans) cnt=c[a[j]],ans=a[j];
    			f[i][pos[j]]=ans;
    		}
    	}
    	for(int x=0,l,r;m--;){
    		l=(read<int>()+x-1)%n+1,r=(read<int>()+x-1)%n+1;
    		if(l>r) swap(l,r);
    		printf("%d
    ",x=ask(l,r));
    	}
    	return 0;
    }
    
  • 相关阅读:
    idea快速生成javaBean快捷键
    2019.10.22 关于java对象的一些理解
    2019.10.21 解决win10电脑qq通话没有声音
    知乎上看到的好的文章
    2019.10.2怎么查看那些ip访问了你的网站
    2019.10.1怎么在服务器上建一个网站
    2019.9.30第一次把自己写的前端东西放在服务器上哈哈
    新手容易犯的错误
    Python3-列表推导式
    Python3-os模块
  • 原文地址:https://www.cnblogs.com/autoint/p/10606701.html
Copyright © 2011-2022 走看看