蒲公英

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;
}
上一篇:[AH2017/HNOI2017]礼物 (FFT)


下一篇:NA西游第五难:OSPF基础配置