【BZOJ 2724】 [Violet 6]蒲公英

2724: [Violet 6]蒲公英

Time Limit: 40 Sec  Memory Limit: 512 MB

Submit: 970  Solved: 319

[Submit][Status][Discuss]

Description

Input

修正一下

l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1

Output

Sample Input

6 3

1 2 3 2 1 2

1 5

3 6

1 5

Sample Output

1

2

1

HINT

修正下:

n <= 40000, m <= 50000

Source

Vani原创

分块。

首先把n个数分成sqrt(n)块,预处理出每一块的开头到他后面所有位置的答案,O(n*sqrt(n))。

对于每一个询问(l,r),我们把它分割成(l,L-1),(L,r),其中L是一个块的开始。

后者已经预处理过了,前者暴力枚举,用二分法计算他在(l,r)的出现次数,更新答案。

(为了求出现次数,我们需要把a[i]离散化,对于每个a[i]按照位置从左到右的顺序记录下来,然后就可以二分了)

时间复杂度O(m*sqrt(n)*logn+n*sqrt(n))

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#define pb push_back
#define M 40005
using namespace std;
int belong[M],cnt[M],n,m,tot,B,num;
vector<int> v[M];
struct data
{
	int hash,id;
}a[M];
struct Ans
{
	int ans,id;
}f[205][M];
struct Help
{
	int pos,v;
}b[M];
void read(int &tmp)
{
	tmp=0;
	char ch=getchar();
	int fu=1;
	for (;ch<'0'||ch>'9';ch=getchar())
		if (ch=='-') fu=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())
		tmp=tmp*10+ch-'0';
	tmp*=fu;
}
void Prepare()
{
	for (int i=1;i<=num;i++)
	{
		for (int j=(i-1)*B+1;j<=i*B;j++)
			belong[j]=i;
		for (int j=1;j<=tot;j++)
			cnt[j]=0;
		Ans x;
		x.ans=0,x.id=0;
		for (int j=(i-1)*B+1;j<=n;j++)
		{
			int h=a[j].hash;
			cnt[h]++;
			if (cnt[h]>x.ans||(cnt[h]==x.ans&&a[j].id<x.id))
				x.ans=cnt[h],x.id=a[j].id;
			f[i][j]=x;
		}
	}
}
bool cmp(Help a,Help b)
{
	if (b.v==a.v) return a.pos<b.pos;
	return a.v<b.v;
}
int Findd(int k,int l,int r,int w)
{
	if (l==r) return l;
	int m=(l+r)>>1;
	if (v[k][m]>w&&m-1>=0&&v[k][m-1]>=w) return Findd(k,l,m-1,w);
	if (v[k][m]<w) return Findd(k,m+1,r,w);
	return m;
}
int Findx(int k,int l,int r,int w)
{
	if (l==r) return l;
	int m=(l+r)>>1;
	if (v[k][m]<w&&m+1<v[k].size()&&v[k][m+1]<=w) return Findx(k,m+1,r,w);
	if (v[k][m]>w) return Findx(k,l,m-1,w);
	return m;
}
int Get(int k,int l,int r)
{
	int s=v[k].size();
	return Findx(k,0,s-1,r)-Findd(k,0,s-1,l)+1;
}
int Solve(int l,int r)
{
	int k=belong[l];
	if ((k-1)*B+1==l) return f[k][r].id;
	Ans x=f[k+1][r];
	for (int i=l;i<=min(k*B,r);i++)
	{
		int now=Get(a[i].hash,l,r);
		if (now>x.ans||(now==x.ans&&a[i].id<x.id))
			x.ans=now,x.id=a[i].id;
	}
	return x.id;
}
int main()
{
	scanf("%d%d",&n,&m);
	tot=0;
    for (int i=1;i<=n;i++)
	{
		read(a[i].id);
		b[i].v=a[i].id,b[i].pos=i;
	}
	sort(b+1,b+1+n,cmp);
	b[0].v=-10;
	for (int i=1;i<=n;i++)
		if (b[i].v==b[i-1].v) a[b[i].pos].hash=tot;
	    else a[b[i].pos].hash=++tot;
	for (int i=1;i<=n;i++)
		v[a[i].hash].pb(i);
	B=sqrt(n);
	num=(n+B-1)/B;
	Prepare();
	int ans=0;
	while (m--)
	{
		int l,r;
		read(l),read(r);
		l=(l+ans-1)%n+1,r=(r+ans-1)%n+1;
		if (l>r) swap(l,r);
		ans=Solve(l,r);
		printf("%d\n",ans);
	}
	return 0;
}

感悟:

1.二分写错;

Solve中要注意(l,r)可能不足一块,所以循环到min(k*B,r)

时间: 2024-10-12 15:32:04

【BZOJ 2724】 [Violet 6]蒲公英的相关文章

BZOJ 2724: [Violet 6]蒲公英

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1633  Solved: 563[Submit][Status][Discuss] Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Outp

[BZOJ 2724] [Violet 6] 蒲公英 【分块】

题目链接:BZOJ - 2724 题目分析 这道题和 BZOJ-2821 作诗 那道题几乎是一样的,就是直接分块,每块大小 sqrt(n) ,然后将数字按照数值为第一关键字,位置为第二关键字排序,方便之后二分查找某个值在某个区间内出现的次数. 预处理出 f[i][j] 即从第 i 块到第 j 块的答案. 对于每个询问,中间的整块直接用预处理出的,两端的 sqrtn 级别的数暴力做,用二分查找它们出现的次数. 每次询问的复杂度是 sqrtn * logn . 注意:写代码的时候又出现了给 sort

【BZOJ 2724】 2724: [Violet 6]蒲公英 (区间众数不带修改版本)

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1908  Solved: 678 Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Output 1 2 1 HINT 修正下: n <= 4

BZOJ2724: [Violet 6]蒲公英

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 795  Solved: 248[Submit][Status] Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input Sample Output HINT 修正下: n <= 40000, m <= 50000 S

二分+最短路判定 BZOJ 2709: [Violet 1]迷宫花园

BZOJ 2709: [Violet 1]迷宫花园 Sample Input 5 10.28 9 9 ######### # # # # # # # #S# # ##### # # ## # # # ### ### ##E # ######### 4.67 9 9 ######### # ## ## ### #S# # # # E ## # # ##### # ## ### # ##### # # # # ######### 39.06 9 9 ######### # # # # # # # #

【BZOJ2724】[Violet 6]蒲公英 分块+二分

[BZOJ2724][Violet 6]蒲公英 Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Output 1 2 1 HINT 修正下: n <= 40000, m <= 50000 题解:分块还是练脑子啊~ 结论:一个区间的众数要么是区间中一个块的众数,要么是块外的任意

「Violet」蒲公英

「Violet」蒲公英 传送门 区间众数,强制在线. 分块经典题. 像这题一样预处理,然后就直接爆搞,复杂度 \(O(n \sqrt n)\) 参考代码: #include <algorithm> #include <cstdio> #include <cmath> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".ou

BZOJ 2725: [Violet 6]故乡的梦 最短路+线段树

2725: [Violet 6]故乡的梦 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 678  Solved: 204[Submit][Status][Discuss] Description Input Output Sample Input 6 7 1 2 1 2 3 1 3 4 2 4 5 1 5 6 1 1 3 3 4 6 3 1 6 4 1 2 1 3 4 3 6 5 Sample Output 7 6 Infinity 7 HINT

BZOJ 2718: [Violet 4]毕业旅行( 最长反链 )

一不小心速度就成了#1.... 这道题显然是求最长反链, 最长反链=最小链覆盖.最小链覆盖就是先做一次floyd传递闭包, 再求最小路径覆盖. 最小路径覆盖=N - 二分图最大匹配. 所以把所有点拆成x,y两个, 然后存在edge(u,v)就连ux->vy. 然后跑匈牙利即可. ------------------------------------------------------------------ #include<bits/stdc++.h> using namespace