l55584 @ 2022-08-29 14:56:34
看着蓝书写的(就是李煜东的《算法竞赛进阶指南》)
将块数T和长度len设置为书上写的
T=sqrt(n*(log(n)/log(2)));
len=n/T;
WA0分
设置为
T=sqrt(n);
len=n/T;
A了
如果可能是我代码的问题,在此附上代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string.h>
#include <cmath>
#define rep(a,b,c) for(register int a=b;a<=c;++a)
using namespace std;
int T,n,m;
typedef long long ll;
const int N=40001;
int len;
//快读------------------------------------------
inline char gc() {
static char BB[1000000],*S=BB,*T=BB;
return S==T&&(T=(S=BB)+fread(BB,1,1000000,stdin),S==T)?EOF:*S++;
}
inline int read() {
int x=0,f=1;
char ch=gc();
while(ch<'0'||ch>'9') {
if(ch=='-') f=-1;
ch=gc();
}
while(ch>='0'&&ch<='9') {
x=x*10+ch-48;
ch=gc();
}
return x*f;
}
//----------------------------------------------
vector<int> dic;
vector<int> d[N];
int p[1001][1001];
int a[N];
void init() {
n=read();
m=read();
//T=sqrt(n*(log(n)/log(2)));
//len=n/T;
T=sqrt(n);
len=n/T;
rep(i,1,n) {
a[i]=read();
dic.push_back(a[i]);
}
//-------------------------------------------------离散化
sort(dic.begin(),dic.end());
int tot=unique(dic.begin(),dic.end())-dic.begin();
rep(i,1,n) a[i]=lower_bound(dic.begin(),dic.begin()+tot,a[i])-dic.begin()+1;
//-------------------------------------------------------
rep(i,1,n) d[a[i]].push_back(i);//为num()查询构建d数组,记录每一种蒲公英的出现位置
int v[N];//桶
//-----------------------------------预处理块间众数
rep(i,1,T) {
memset(v,0,sizeof v);
int mmax[2]= {0,0};
rep(j,i,T) {
int r=j*len,l=r-len+1;
rep(k,l,r) {
v[a[k]]++;
if(v[a[k]]>mmax[0]||(v[a[k]]==mmax[0]&&a[k]<mmax[1])) {//取编号最小
mmax[0]=v[a[k]],mmax[1]=a[k];
}
}
p[i][j]=mmax[1];//p[i][j]记录第i块到第j块(左闭右闭)众数
}
}
//--------------------------------------------------
}
inline int num(int k,int l,int r) {//求区间k类蒲公英的数量
int up=upper_bound(d[k].begin(),d[k].end(),r)-d[k].begin()-1;
int down=lower_bound(d[k].begin(),d[k].end(),l)-d[k].begin();
return up-down+1;
}
int query(int l,int r) {
int L=ceil(l*1.0/len)+1,R=ceil(r*1.0/len)-1;//区间内可用块的区间
int now=num(p[L][R],l,r),ret=p[L][R];
rep(i,l,(L-1)*len) {//trival左边
int cnt=num(a[i],l,r);
if(cnt>now||(cnt==now&&a[i]<ret)) {//注意取编号最小
now=cnt;
ret=a[i];
}
}
rep(i,(R*len)+1,r) {//trival右边
int cnt=num(a[i],l,r);
if(cnt>now||(cnt==now&&a[i]<ret)) {//注意取编号最小
now=cnt;
ret=a[i];
}
}
return ret;
}
int main() {
//freopen("in.in","r",stdin);
//freopen("P4168_1.in","r",stdin);
//freopen("out.out","w",stdout);
init();
ll l,r,lasans=0;
rep(i,1,T) {
// rep(j,i,T) cout<<(i-1)*len+1<<" "<<j*len<<" "<<p[i][j]<<"\n";
}
rep(k,1,m) {
l=read(),r=read();
l=(l+lasans-1)%n+1;
r=(r+lasans-1)%n+1;
if(l>r) swap(l,r);
lasans=dic[query(l,r)-1];//还原,注意-1
cout<<lasans<<endl;
}
return 0;
}
by yinhee @ 2022-08-29 15:15:50
您这样块数就是
by l55584 @ 2022-08-29 15:24:50
@yinhee 这个算法复杂度为O(NT+MN/T*logN)
块数应该设为
我是这么想的,书上也是这么写的。
或许是我理解错了?可以再详细说一下吗
by Texas_the_Omertosa @ 2022-08-29 15:25:23
@l55584 我经常照蓝书写,经常 WA,所以我现在经常就是看蓝书学理论,代码不知道怎么写就看题解。
by Texas_the_Omertosa @ 2022-08-29 15:26:37
@l55584 块的长度一般设为
by l55584 @ 2022-08-29 15:27:01
@olkieler 谢谢建议,帮大忙了
by l55584 @ 2022-08-29 15:29:25
@olkieler 这样时间复杂度会不会出现错误的情况?
好像也不一定……比如莫队用sqrtN会被卡
by Texas_the_Omertosa @ 2022-08-29 15:32:58
@l55584 我刚学分块,莫队还没学(我连那是什么都不知道),我觉得分块没有线段树好写,就只学了理论。