题意

4401 蒲公英 0x40「数据结构进阶」例题

描述

题目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\n",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\n",x=ask(l,r));
}
return 0;
}

CH4401 蒲公英的更多相关文章

  1. App内测神器之蒲公英

    一.前言部分 没使用蒲公英之前一直采用非常傻B的方式给公司App做内部测试,要么发个测试包让公司测试人员用iTUnes 自己安装 要么苦逼的一个个在我Xcode上直接安装测试包,操作起来又麻烦又苦逼, ...

  2. BZOJ 2724: [Violet 6]蒲公英

    2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1633  Solved: 563[Submit][Status ...

  3. [BZOJ2724][Violet 6]蒲公英

    [BZOJ2724][Violet 6]蒲公英 试题描述 输入 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 输出 输入示 ...

  4. iOS 使用fir、 蒲公英 进行内部测试

    fir 蒲公英需要去注册账号并认证,按提示即可完成. 测了公司账号.个人开发账号,2个都可以用,就是要在配置文件里加上测试者的udid. 步骤: 1.添加测试机的udid edit配置文件,添加刚刚加 ...

  5. BZOJ 2724: [Violet 6]蒲公英( 分块 )

    虽然AC了但是时间惨不忍睹...不科学....怎么会那么慢呢... 无修改的区间众数..分块, 预处理出Mode[i][j]表示第i块到第j块的众数, sum[i][j]表示前i块j出现次数(前缀和, ...

  6. iOS 打包上传AppStore相关(3)-iTunes相应配置以及使用蒲公英网站进行应用托管分发(链接/二维码)

    上一篇讲到我们最终生成了一个格式为 .xcarchive 的文件(可以右键并Show in Finder)查看.本篇我们就进行最后的设置,打包上传.另外,还有一个小福利,那就是打测试包分发链接测试. ...

  7. 【MFC】利用双缓冲和随机函数rand()实现蒲公英飞舞

    原始日期:2014-05-29 22:44 这几天有些懒,几乎没怎么学MFC了,好容易有个题目:用双缓冲实现蒲公英飞舞,想来想去也没想到好方法,索性动手开始 写了 ,这一写,得,出来了,呵呵,无意中产 ...

  8. BZOJ_2724_[Violet 6]蒲公英_分块

    BZOJ_2724_[Violet 6]蒲公英_分块 Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod ...

  9. 【最新】Android使用jenkins全自动构建打包-Windows版本(Android,Jenkins,360加固,Email,QRcode,参数构建,蒲公英)

    Android打包喝咖啡系列(Windows版) 这篇博客主要讲述的内容: 1.windows上部署Jenkins https://jenkins.io 2.基于SVN或Git https://git ...

随机推荐

  1. Unix分类学习

    调试 shell # bash -x script.sh 设置终端背景色 setterm -background black 一.网络 1.网卡状态 mii-tool -v ethtool eth0 ...

  2. vue-5-列表渲染

    一个数组的v-for<ul id="example-1"> <li v-for="item in items"> {{ item.mes ...

  3. L1-056 猜数字

    一群人坐在一起,每人猜一个 100 以内的数,谁的数字最接近大家平均数的一半就赢.本题就要求你找出其中的赢家. 输入格式: 输入在第一行给出一个正整数N(≤10​4​​).随后 N 行,每行给出一个玩 ...

  4. 关于时间戳截取的隐藏bug

    之前写时间戳,要截取后六位 原写法: function timeStamp() { const date = new Date() const month = date.getMonth() + 1 ...

  5. leetcode第39题:组合综合

    给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无限制重复被选 ...

  6. leetcode第72题:编辑距离

    给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 . 你可以对一个单词进行如下三种操作: 插入一个字符 删除一个字符 替换一个字符 示例 1: 输 ...

  7. Linux:http配置

    http配置 1.挂载系统:mount /dev/cdrom /mnt/cdrom2.安装:rpm -ivh httpd-2.4.6-88.el7.centos.x86_64.rpm2.启动服务:sy ...

  8. golang切片类型

    切片slice 其本身并不是数组,它指向底层的数组 作为变长数组的替代方案,可以关联底层数组的局部或全部 为引用类型 可以直接创建或从底层数组获取生成 使用len()获取元素个数,cap()获取容量 ...

  9. jquery.datatables设置列隐藏的方法

    项目需要根据权限设置表格(使用Juqery.datatables,版本:1.10.16)某列显示或隐藏,百度后有两种实现方法: 1.在columns中设置: columns:[{data:" ...

  10. Python写一个批量生成账号的函数

    批量生成账户信息,产生的账户由@sina.com结尾,长度由用户输入,产生多少条也由用户输入,用户名不能重复,用户名必须由大写字母.小写字母和数字组成. def Users(num,len): # n ...