首先預處理出對於每個模數,所有被模數按結果從大到小排序的結果,那麼對於一個詢問,如果可以在$O(1)$時間內判斷某個數字是否出現,則可以$O(1000)$回答。
考慮對序列進行分治,對於區間$[l,r]$,取$mid=\lfloor\frac{l+r}{2}\rfloor$。
處理出$mid$到$[l,r]$內每個位置裡每個數字的出現次數,回答所有經過$mid$的詢問,然後遞迴分治$[l,mid)$和$(mid,r]$。
時間複雜度$O((n+m)\log n+1000m)$。
#include<cstdio> #include<algorithm> using namespace std; const int N=1000010,M=50010,K=1010,BUF=9000000; char Buf[BUF],*buf=Buf; inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;} int n,m,i,j,x,y,a[N],gl[N],gr[N],v[M<<1],nxt[M<<1],ed,b[K],q[K][K];bool c[K]; struct E{int x,y,p,l,r;}e[M]; inline bool cmp(int x,int y){return b[x]>b[y];} inline void add(int&x,int y){v[++ed]=y;nxt[ed]=x;x=ed;} inline void check(int x,int l,int r,int&y){ if(~y||e[x].x>l||e[x].y<r)return; for(int i=0,p=e[x].p;;i++)if(c[q[p][i]]){y=q[p][i]%p;return;} } void solve(int l,int r){ if(l>r)return; int mid=(l+r)>>1,i,j; for(i=mid;i>=l;i--)for(c[a[i]]=1,j=gl[i];j;j=nxt[j])check(v[j],i,mid,e[v[j]].l); for(i=mid;i>=l;i--)c[a[i]]=0; for(i=mid;i<=r;i++)for(c[a[i]]=1,j=gr[i];j;j=nxt[j])check(v[j],mid,i,e[v[j]].r); for(i=mid;i<=r;i++)c[a[i]]=0; solve(l,mid-1),solve(mid+1,r); } int main(){ fread(Buf,1,BUF,stdin);read(n),read(m); for(i=1;i<=n;i++)read(a[i]); for(i=1;i<=m;i++){ read(x),read(y); if(x>y)swap(x,y); add(gl[e[i].x=x+1],i),add(gr[e[i].y=y+1],i); read(e[i].p),e[i].l=e[i].r=-1; } for(i=2;i<=1000;i++){ for(j=0;j<=1000;j++)b[j]=j%i,q[i][j]=j; sort(q[i],q[i]+1001,cmp); } solve(1,n); for(i=1;i<=m;i++)printf("%d\n",max(e[i].l,e[i].r)); return 0; }