修正一下
l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1
修正下:
n <= 40000, m <= 50000
分块。
首先把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)
原文地址:http://blog.csdn.net/regina8023/article/details/44860807