https://www.luogu.com.cn/problem/P4168

题目

给$n$个数字,有$m$次询问,问$a_l, a_{l+1} , \dots , a_r$的众数是什么,

$1\leqslant n \leqslant 40000, 1\leqslant m \leqslant 50000, 1\leqslant a_i\leqslant10^9$

题解

第一次做分块

方法一

因为n不是很大,所以可以对数据进行离散化后统计出现次数

所以就可以直接统计最大的了。这样复杂度是$\mathcal{O}(m\times n)$,肯定超时

可以尝试提前分块打出一些表,比如分成$t$块,然后提前打好$\binom{t}{2}$块的最大值,并保存是哪一个

那么每次查询的时候最多花$2\times \lfloor n/t\rfloor$的时间,时间复杂度是$\mathcal{O}(t^2n+2mn/t)$

把$m$和$n$看作同数量级,设为N,那么得到$t^2N+2N^2/t$,为了保证数量级相同,设$t^2N=2N^2/t$,得到$t=\sqrt[3]{N}$

因为大于或小于以后两边渐进复杂度都会增加,导致整个表达式的渐进复杂度增加(算法导论:证明$max(a,b)=\Theta(a+b)$)

AC代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<cmath>
  5. #include<queue>
  6. #include<vector>
  7. using namespace std;
  8. #define REP(i,a,b) for(register int i=(a); i<(b); i++)
  9. #define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
  10. #define PERE(i,a,b) for(register int i=(a); i>=(b); i--)
  11. #ifdef sahdsg
  12. #define DBG(...) printf(__VA_ARGS__)
  13. #else
  14. #define DBG(...) void(0)
  15. #endif
  16. typedef long long ll;
  17. #define MAXN 40007
  18. #define MAXM 50007
  19. #define MAXD 35
  20. int a[MAXN], b[MAXN], c[MAXN];
  21. int d[MAXD][MAXD][MAXN];
  22. int now[MAXN];
  23. int t,l,na;
  24. int x=0;
  25. inline void did(int f) {
  26. now[f]++;
  27. if(now[na]<now[f] || (now[na]==now[f] && now[na+1]>f)) {
  28. now[na+1]=f;
  29. now[na]=now[f];
  30. }
  31. }
  32. inline int go(int z, int y) {
  33. int i=(z+l-1)/l, j=y/l;
  34. int L=i*l, R=j*l;
  35. if(i<j) {
  36. REP(k,0,na+2)
  37. now[k] = d[i][j][k];
  38. REP(f,z,L) did(c[f]);
  39. REP(f,R,y) did(c[f]);
  40. } else {
  41. memset(now,0,sizeof now);
  42. REP(f,z,y) did(c[f]);
  43. }
  44. return x=b[now[na+1]];
  45. }
  46. int main() {
  47. int n,m; scanf("%d%d", &n, &m);
  48. REP(i,0,n) {scanf("%d", &a[i]); b[i]=a[i];}
  49. sort(b,b+n); na = unique(b,b+n)-b;
  50. REP(i,0,n) {
  51. c[i] = lower_bound(b,b+na,a[i])-b;
  52. }
  53. memset(d,0,sizeof d);
  54. t = pow((double)n, (double)1/3);
  55. l = t ? n/t : n;
  56. REP(i,0,t) REPE(j,i,t) {
  57. REP(f,i*l,j*l) {
  58. int k = c[f];// DBG("*%d\n", k);
  59. d[i][j][k]++;
  60. if(d[i][j][k]>d[i][j][na] || (d[i][j][k]==d[i][j][na] && k<d[i][j][na+1])) {
  61. d[i][j][na] = d[i][j][k];
  62. d[i][j][na+1] = k;
  63. }
  64. }
  65. }
  66.  
  67. REP(i,0,m) {
  68. int l0, r0;
  69. scanf("%d%d", &l0, &r0);
  70. int l = (l0 + x - 1) % n + 1;
  71. int r = (r0 + x - 1) % n + 1;
  72. if(l>r) swap(l,r);
  73. go(l-1,r);
  74. printf("%d\n", x);
  75. }
  76. return 0;
  77. }

方法二

用同样的分块方法,但是只记录最大值,不记录次数,而使用二分确定大小,一次二分确定大小需要$\mathcal{O}(\log n)$。

设需要分$D$块,然后得到时间复杂度$\mathcal{O}(D\times N+2MN/D\log n)$(因为剩下部分最长是两个块,虽然比平均情况大,但是为了应付数据,数据是最大的很多……)

那么用相同的方法,解得$D=\sqrt{2N\log N}$

中间有个细节,就是计算D和L的时候要考虑是偏大还是篇小,由于我快断电了,所以坑了

AC代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<cmath>
  5. #include<queue>
  6. #include<vector>
  7. #include<cassert>
  8. using namespace std;
  9. #define REP(i,a,b) for(register int i=(a); i<(b); i++)
  10. #define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
  11. #define PERE(i,a,b) for(register int i=(a); i>=(b); i--)
  12. #ifdef sahdsg
  13. #define DBG(...) printf(__VA_ARGS__)
  14. #else
  15. #define DBG(...) void(0)
  16. #endif
  17. typedef long long ll;
  18. #define MAXN 50007
  19. #define MAXM 50007
  20. #define MAXL 1007
  21. #define MAXD 884*2
  22. int a[MAXN],b[MAXN],c[MAXN],nb;
  23. int fk[MAXD][MAXD], L, D;
  24. int cnt[MAXN], nmax, ncnt;
  25. int x=0;
  26. vector<int> arr[MAXN];
  27. int calc(int l, int r, int b) {
  28. //r--;
  29. return lower_bound(arr[b].begin(), arr[b].end(), r)-lower_bound(arr[b].begin(), arr[b].end(), l);
  30. }
  31. void did(int l, int r, int b) {
  32. int t=calc(l,r,b);
  33. if(t>ncnt || (t==ncnt && b<nmax)) {
  34. ncnt=t;
  35. nmax=b;
  36. }
  37. }
  38. void work(int l, int r) {
  39. nmax=0, ncnt=0;
  40. int z=(l+L-1)/L, y=r/L;
  41. if(z<y) {
  42. int Z=z*L, Y=y*L;
  43. REP(i,l,Z) did(l,r,c[i]);
  44. REP(i,Y,r) did(l,r,c[i]);
  45. did(l,r,fk[z][y]);
  46. } else {
  47. REP(i,l,r) did(l,r,c[i]);
  48. }
  49. x=b[nmax];
  50. }
  51. int main() {
  52. int n,m; scanf("%d%d", &n, &m);
  53. REP(i,0,n) {
  54. scanf("%d", &a[i]);
  55. b[i]=a[i];
  56. }
  57. sort(b,b+n);
  58. nb = unique(b,b+n)-b;
  59. REP(i,0,n) {
  60. c[i] = lower_bound(b,b+nb,a[i])-b;
  61. }
  62. D = sqrt(log((double)n)/log(2.0)*n*2); if(D==0) D=1;
  63. L = n/D; //L<L' D>D'
  64. D = n/L; //L>L' D<D'
  65. REP(i,0,D) {
  66. int s=i*L;
  67. nmax = 0, ncnt = 0;
  68. REP(k,0,n) cnt[k]=0;
  69. REP(j,s,n) {
  70. int J=(j+1+L-1)/L, k=c[j];
  71. cnt[k]++;
  72. if(cnt[k]>ncnt ||(cnt[k]==ncnt && k<nmax)) {
  73. ncnt = cnt[k];
  74. nmax = k;
  75. }
  76. fk[i][J]=nmax;
  77. }
  78. }
  79. REP(i,0,n) {
  80. arr[c[i]].push_back(i);
  81. }
  82. REP(i,0,m) {
  83. int l,r;
  84. scanf("%d%d", &l, &r);
  85. l = (l+x-1)%n+1, r=(r+x-1)%n+1;
  86. if(l>r) swap(l,r);
  87. work(l-1,r);
  88. printf("%d\n", x);
  89. }
  90. }

Violet 6 杯省选模拟赛 蒲公英的更多相关文章

  1. Contest Hunter Round #70 - 连续两大交易事件杯省选模拟赛

    orz lydrainbowcat [Problem A]「艦これ市」70万幕后交易事件 排序机器=-=.重要的是相同的处理. 我们可以从小到大添加数字,然后维护一个位置的序列.每一种相等的数字都在一 ...

  2. codehunter 「Adera 6」杯省选模拟赛 网络升级 【树形dp】

    直接抄ppt好了--来自lyd 注意只用对根判断是否哟留下儿子 #include<iostream> #include<cstdio> using namespace std; ...

  3. 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解

    今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...

  4. @省选模拟赛03/16 - T3@ 超级树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...

  5. 3.28 省选模拟赛 染色 LCT+线段树

    发现和SDOI2017树点涂色差不多 但是当时这道题模拟赛的时候不会写 赛后也没及时订正 所以这场模拟赛的这道题虽然秒想到了LCT和线段树但是最终还是只是打了暴力. 痛定思痛 还是要把这道题给补了. ...

  6. 省选模拟赛第四轮 B——O(n^4)->O(n^3)->O(n^2)

    一 稍微转化一下,就是找所有和原树差距不超过k的不同构树的个数 一个挺trick的想法是: 由于矩阵树定理的行列式的值是把邻接矩阵数值看做边权的图的所有生成树的边权乘积之和 那么如果把不存在于原树中的 ...

  7. NOI2019省选模拟赛 第五场

    爆炸了QAQ 传送门 \(A\) \(Mas\)的童年 这题我怎么感觉好像做过--我记得那个时候还因为没有取\(min\)结果\(100\to 0\)-- 因为是个异或我们肯定得按位考虑贡献了 把\( ...

  8. NOI2019省选模拟赛 第六场

    传送门 又炸了-- \(A\) 唐时月夜 不知道改了什么东西之后就\(A\)掉了\(.jpg\) 首先,题目保证"如果一片子水域曾经被操作过,那么在之后的施法中,这片子水域也一定会被操作&q ...

  9. 省选模拟赛 arg

    1 arg (arg.cpp/in/out, 1s, 512MB)1.1 Description给出一个长度为 m 的序列 A, 请你求出有多少种 1...n 的排列, 满足 A 是它的一个 LIS. ...

随机推荐

  1. USB3.0之高速视频传输测试 双目相机(mt9p031、mt9m001)带宽高达300M测试 配合isensor测试 500万像素15fps

    最近完善了下USB3.0的视频开发测试,主要优化了FPGA程序和固件,及其同步方式.对带宽和图像效果进行了仔细的测试 开发板架构(2CMOS+FPGA+2DDR2+USB3.0) 评估板底板配合2个M ...

  2. 从零开始的openGL——五、光线追踪

    前言 前面介绍了基本图形.模型.曲线的绘制,但是,在好像还没有感受到那种3D游戏里一些能惊艳到自己的效果,即真实感还不是很足.这篇文章中介绍的光线追踪,是实现真实感必不可少的.拿下面的两张图片来对比 ...

  3. 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享 工程代码地址 思维导图地址 工程结构图: 正 ...

  4. angular6路由参数的传递与获取

    1.访问路由链接:/test/id 路由配置: {path: 'test/:id', component: TestComponent} html传参: <a href="javasc ...

  5. 【玩转SpringBoot】看似复杂的Environment其实很简单

    喜欢写代码,讨厌配环境 我相信这十个字的小标题代表了大多数码农的心声. 十年前读大学时,学校开设了C语言还有C++.但是学习这两种语言,对于新手来说非常没有成就感. 于是我就在校门口买个光盘,装个VS ...

  6. android开发检测用户是否使用了虚拟定位

    在应用开发中,如果有签到打卡之类的功能,你是否会遇到检测用户是否使用了虚拟定位软件来进行打卡?如果有,那么请仔细阅读这篇文章.该文章会带你认识什么是虚拟定位.什么是应用分身,以及如何通过代码来检测用户 ...

  7. Mysql服务彪高排查方式及索引的正确使用步骤

    原文内容来自于LZ(楼主)的印象笔记,如出现排版异常或图片丢失等问题,可查看当前链接:https://app.yinxiang.com/shard/s17/nl/19391737/12af580d-1 ...

  8. nfs 所有的版本的 RFC 整理; nfs 所有版本对比;

    下面是针对 nfs 所有的版本,我们可以通过不同的RFC 进行详细看其RFC的细节来进行对比: 下面是备忘一些NFS RFC 的链接: https://datatracker.ietf.org/doc ...

  9. JavaWeb 实现简单登录、注册功能

    1.首先创建一个简单的动态Javaweb项目 2.然后手动建立文件目录: 项目创建好之后,在src下建几个包: controller:控制器,负责转发请求,对请求进行处理,主要存放servlet: d ...

  10. 面试连环炮系列(四):说说TCP的三次握手过程

    说说TCP三次握手的过程? 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认. 第二次 ...