L. Mod(预处理+分块)
生活随笔
收集整理的這篇文章主要介紹了
L. Mod(预处理+分块)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
L.Mod
題目大意
給定一個序列和 l,r,kl,r, kl,r,k,詢問 [l,r][l,r][l,r] 中的數字 mod kkk 的最大值,1≤n,k≤500001\leq n,k\leq 500001≤n,k≤50000
分塊,預處理fi,jf_{i,j}fi,j?表示第iii塊mod jjj的最大值。
對于每一塊,維護 mximx_imxi?, 表示本塊內所有出現過的數字中不小于iii的最大的數字。
對于fi,jf_{i,j}fi,j?,依次枚舉長度為jjj的區間[k×j,k×j+j?1][k×j,k×j+j-1][k×j,k×j+j?1],于是有
fi,j=max?k{mxk×j+j?1?k×j}f_{i,j}=\max_{k}\{\text{mx}_{k×j+j-1}-k×j\}fi,j?=kmax?{mxk×j+j?1??k×j}
設塊的大小為B\text BB
時間復雜度為O{NBNlog?N+M(B+NB)}O\{\frac N{\text B}N\log N+M(\text B+\frac N{\text B})\}O{BN?NlogN+M(B+BN?)}
取B=N+N2log?NM\text B=\sqrt{N+\frac{N^2\log N}{M}}B=N+MN2logN??最優
Code
此代碼并未經過驗證,無意間看到之前校賽的題目,貌似已經沒有oj去測評。。。
#include<bits/stdc++.h> using namespace std; using ll=long long; template <class T=int> T rd() {T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg; } const int N=50010; int n,m; int a[N]; int b[N],Bs; int f[400][N],mx[N]; void prework() {Bs=sqrt(10*n);for(int i=1;i<=n;i++) b[i]=(i-1)/Bs+1;for(int i=1;i<b[n];i++){for(int k=(b[i]-1)*Bs+1;k<b[i]*Bs;k++) mx[a[k]]=a[k];memeset(mx,0,sizeof mx);for(int j=1;j<=50000;j++) mx[j]=max(mx[j],mx[j-1]);for(int j=1;j<=50000;j++)for(int k=1;k*j+j-1<=50000;k++)f[i][j]=max(f[i][j],mx[k*j+j-1]-k*j);} } int query(int l,int r,int v) {int ans=0;for(int i=l;i<=min(r,Bs*b[l]);i++) ans=max(ans,a[i]%v);if(b[l]!=b[r]) for(int i=(b[r]-1)*Bs+1;i<=r;i++) ans=max(ans,a[i]%v);for(int i=b[l]+1;i<b[r];i++) ans=max(ans,f[i][v]);return ans; } int main() {n=rd(),m=rd();for(int i=1;i<=n;i++) a[i]=rd();prework();while(m--) {int l=rd(),r=rd(),k=rd();printf("%d\n",query(l,r,k));}return 0; }總結
以上是生活随笔為你收集整理的L. Mod(预处理+分块)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021牛客暑期多校训练营3 B-Bla
- 下一篇: 2021牛客暑期多校训练营1 J-Jou