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代码
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #include<vector> using namespace std; #define REP(i,a,b) for(register int i=(a); i<(b); i++) #define REPE(i,a,b) for(register int i=(a); i<=(b); i++) #define PERE(i,a,b) for(register int i=(a); i>=(b); i--) #ifdef sahdsg #define DBG(...) printf(__VA_ARGS__) #else #define DBG(...) void(0) #endif typedef long long ll; #define MAXN 40007 #define MAXM 50007 #define MAXD 35 int a[MAXN], b[MAXN], c[MAXN]; int d[MAXD][MAXD][MAXN]; int now[MAXN]; int t,l,na; int x=0; inline void did(int f) { now[f]++; if(now[na]<now[f] || (now[na]==now[f] && now[na+1]>f)) { now[na+1]=f; now[na]=now[f]; } } inline int go(int z, int y) { int i=(z+l-1)/l, j=y/l; int L=i*l, R=j*l; if(i<j) { REP(k,0,na+2) now[k] = d[i][j][k]; REP(f,z,L) did(c[f]); REP(f,R,y) did(c[f]); } else { memset(now,0,sizeof now); REP(f,z,y) did(c[f]); } return x=b[now[na+1]]; } int main() { int n,m; scanf("%d%d", &n, &m); REP(i,0,n) {scanf("%d", &a[i]); b[i]=a[i];} sort(b,b+n); na = unique(b,b+n)-b; REP(i,0,n) { c[i] = lower_bound(b,b+na,a[i])-b; } memset(d,0,sizeof d); t = pow((double)n, (double)1/3); l = t ? n/t : n; REP(i,0,t) REPE(j,i,t) { REP(f,i*l,j*l) { int k = c[f];// DBG("*%d\n", k); d[i][j][k]++; if(d[i][j][k]>d[i][j][na] || (d[i][j][k]==d[i][j][na] && k<d[i][j][na+1])) { d[i][j][na] = d[i][j][k]; d[i][j][na+1] = k; } } } REP(i,0,m) { int l0, r0; scanf("%d%d", &l0, &r0); int l = (l0 + x - 1) % n + 1; int r = (r0 + x - 1) % n + 1; if(l>r) swap(l,r); go(l-1,r); printf("%d\n", x); } return 0; }