OneInDark对众数的爱

前言

找不到在哪里提交只能口胡了。

题目

找到了!

蒲公英(洛谷)

还有一道类似的

[Ynoi2019 模拟赛] Yuno loves sqrt technology III(洛谷)

题目描述

( exttt{OneInDark}) 有一个长度为 (n) 的序列 (a)

这一天他找到了你,由于他很喜欢热闹,所以他想询问区间内的众数是什么。

他很专一,所以如果有多个答案,只需要输出编号最小的即可。

而且他喜欢一问一答的交互方式,所以这道题是强制在线。

因为他很强,所以他早就算出了答案,只是需要你与他对一下答案而已。

他有时候也喜欢整蛊,所以他需要你在 (2s) 内算出答案,不然会遭到惩罚。

数据范围

( exttt{OneInDark}) 还是很善解人意的,所以他不会让你很累。

(nle 4*10^4,mle 5*10^4,a_ile 10^9)

讲解

首先我们可以离散化。

考虑分块。

我们可以先用 (O(nsqrt{n})) 的时间复杂度预处理出任意两个块之间形成的区间的众数,以及其出现次数。

我们令 (f[l][r]) 表示 块(l) 到 块(r) 的众数。

对于每个询问,我们考虑答案只可能是这两种情况:

  • 在大块中。

  • 在零散小块中。

对于第一种情况,答案就是 (f[l][r])

对于第二种情况,我们考虑零散的数只有 (sqrt{n}) 级别个。

对于每个数,我们记录一下它们出现的位置(预处理)。

然后我们对于零散的数可以二分出其在区间内的出现次数。

时间复杂度为 (O(msqrt{n}logn))好像已经可以过了

考虑优化。

我们令 (pos[i][j]) 表示 (i) 在数列中第 (j) 次出现的位置。

(t[i]) 表示 (a[i]) 在数列中是第几次出现。

显然我们枚举的零散的数的时候,我们可以将其当做第一次出现。

此时我们需要一个计数的变量 (MAX),其初值为 (f[l][r])

如果当前枚举的这个数 (a[i]),满足 (pos[a[i]][MAX] le qr) (qr为询问区间的右端点)。

那么我们可以继续向右扩展,显然 (MAX) 总共最多只会扩展 (sqrt{n}) 级别次。

(n,m) 基本同阶,所以总时间复杂度为 (O(nsqrt{n}))

代码

蒲公英

//12252024832524
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 40005;
const int MAXB = 205;
int n,m,lshtot,ans,B;
int to[MAXN];
struct node
{
	int val,lsh,ID;
}s[MAXN];
bool cmp1(node x,node y){return x.val < y.val;}
bool cmp2(node x,node y){return x.ID < y.ID;}

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x);
	if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

int f[MAXB][MAXB],cs[MAXB][MAXB],bl[MAXN];
int cnt[MAXN],t[MAXN];
vector<int> pos[MAXN];

void pre()
{
	for(int i = 1;i <= lshtot;++ i) pos[i].push_back(0);
	for(int i = 1;i <= n;++ i) pos[s[i].lsh].push_back(i),t[i] = pos[s[i].lsh].size()-1;
	for(int i = 1;i <= n;i += B)
	{
		int zs = n+1;//众数 
		for(int j = i;j <= n;++ j)
		{
			int val = s[j].lsh;
			cnt[val]++;
			if(cnt[val] > cnt[zs] || (cnt[val] == cnt[zs] && val < zs)) zs = val;
			if(bl[j] != bl[j+1]) f[bl[i]][bl[j]] = zs,cs[bl[i]][bl[j]] = cnt[zs];
		}
		for(int j = i;j <= n;++ j) cnt[s[j].lsh] = 0;
		if(i == 1) i--;
	}
}
int spsolve(int l,int r)
{
	int ret = 0;
	for(int i = l;i <= r;++ i)
	{
		int val = s[i].lsh;
		cnt[val]++;
		if(cnt[val] > cnt[ret] || (cnt[val] == cnt[ret] && val < ret)) ret = val;
	}
	for(int i = l;i <= r;++ i) cnt[s[i].lsh] = 0;
	return ret;
}
int solve(int l,int r)
{
	int L = bl[l],R = bl[r],ret = 0;
	if(L == R) return spsolve(l,r);
	if(bl[l] == bl[l-1]) L++;
	if(bl[r] == bl[r+1]) R--;
	if(L <= R) ret = f[L][R];
	int MAX = cs[L][R];
	for(int i = l;bl[i] != L;++ i)
	{
		int now = t[i],val = s[i].lsh;
		while(pos[val].size()-1 >= now + MAX && pos[val][now+MAX] <= r) MAX++,ret = val;
		if(pos[val].size()-1 >= now + MAX - 1 && pos[val][now+MAX-1] <= r && val < ret) ret = val;
	}
	for(int i = (R+1)*B;i <= r;++ i)
	{
		int now = t[i],val = s[i].lsh;
		while(now - MAX > 0 && pos[val][now-MAX] >= l) MAX++,ret = val;
		if(now - MAX + 1 > 0 && pos[val][now-MAX+1] >= l && val < ret) ret = val;
	}
	return ret;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); m = Read();
	for(int i = 1;i <= n;++ i) s[i].val = Read(),s[i].ID = i;
	sort(s+1,s+n+1,cmp1);
	for(int i = 1;i <= n;++ i)
		if(s[i].val == s[i-1].val) s[i].lsh = s[i-1].lsh;
		else s[i].lsh = ++lshtot,to[lshtot] = s[i].val;
	sort(s+1,s+n+1,cmp2);
	B = sqrt(n);
	for(int i = 1;i <= n;++ i) bl[i] = i / B;
	pre();
	for(int i = 1;i <= m;++ i)
	{
		int l = (Read() + ans - 1) % n + 1,r = (Read() + ans - 1) % n + 1;
		if(l > r) swap(l,r);
		Put(ans = to[solve(l,r)],'
');
	}
	return 0;
}

Yuno loves sqrt technology III

这种离散化更快哦

//12252024832524
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 500005;
const int MAXB = 710;
int n,m,len,ans,B;
int a[MAXN],b[MAXN];

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x);
	if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

int f[MAXB][MAXB],cs[MAXB][MAXB],bl[MAXN];
int cnt[MAXN],t[MAXN];
vector<int> pos[MAXN];

void pre()
{
	for(int i = 1;i <= len;++ i) pos[i].push_back(0);
	for(int i = 1;i <= n;++ i) pos[a[i]].push_back(i),t[i] = pos[a[i]].size()-1;
	for(int i = 1;i <= n;i += B)
	{
		int zs = n+1;//众数 
		for(int j = i;j <= n;++ j)
		{
			int val = a[j];
			cnt[val]++;
			if(cnt[val] > cnt[zs] || (cnt[val] == cnt[zs] && val < zs)) zs = val;
			if(bl[j] != bl[j+1]) f[bl[i]][bl[j]] = zs,cs[bl[i]][bl[j]] = cnt[zs];
		}
		for(int j = i;j <= n;++ j) cnt[a[j]] = 0;
		if(i == 1) i--;
	}
}
int spsolve(int l,int r)
{
	int ret = 0;
	for(int i = l;i <= r;++ i)
	{
		int val = a[i];
		cnt[val]++;
		if(cnt[val] > cnt[ret] || (cnt[val] == cnt[ret] && val < ret)) ret = val;
	}
	ret = cnt[ret];
	for(int i = l;i <= r;++ i) cnt[a[i]] = 0;
	return ret;
}
int solve(int l,int r)
{
	int L = bl[l],R = bl[r];
	if(L == R) return spsolve(l,r);
	if(bl[l] == bl[l-1]) L++;
	if(bl[r] == bl[r+1]) R--;
	int MAX = cs[L][R];
	for(int i = l;bl[i] != L;++ i)
	{
		int now = t[i],val = a[i];
		while(pos[val].size()-1 >= now + MAX && pos[val][now+MAX] <= r) MAX++;
	}
	for(int i = (R+1)*B;i <= r;++ i)
	{
		int now = t[i],val = a[i];
		while(now - MAX > 0 && pos[val][now-MAX] >= l) MAX++;
	}
	return MAX;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); m = Read();
	for(int i = 1;i <= n;++ i) a[i] = b[i] = Read()+1;
	sort(b+1,b+n+1);
	len = unique(b+1,b+n+1)-b;
	for(int i = 1;i <= n;++ i) a[i] = lower_bound(b+1,b+len+1,a[i])-b;
	B = sqrt(n);
	for(int i = 1;i <= n;++ i) bl[i] = i / B;
	pre();
	for(int i = 1;i <= m;++ i)
	{
		int l = Read() ^ ans,r = Read() ^ ans;
		if(l > r) swap(l,r);
		Put(ans = solve(l,r),'
');
	}
	return 0;
}
原文地址:https://www.cnblogs.com/PPLPPL/p/14406875.html