首先对于一个数a【j】,如果他前面某个数对他取模一定是在(0,a【j】-1)之间,那么不难想到如果他前面存在a【i】的话,最大值应该是越靠区间右值越好,那么我们可以这样做:对于每个数a【j】 把可能对他取模的数他分成(0,a【j】-1)(a【j】,2*a【j】-1)。。。若干个区间,然后判断是否有a【i】位于这些区间,如果有的话最大值更新为最靠区间右值的,可以预见如果要实现这些更新和查询操作就应该要用到线段树。
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <bitset> #include <vector> #include <string> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int maxn=500005; const int inf=0x7fffffff; int a[maxn],last[maxn],bit[maxn]; void build(int l,int r,int id) { bit[id]=0; if(l==r) { return; } int m=l+(r-l)/2; build(l,m,id<<1); build(m+1,r,id<<1|1); } int query(int ql,int qr,int l,int r,int id) { if(ql<=l&&qr>=r) { return bit[id]; } int m=l+(r-l)/2; int res=-inf; if(ql<=m) res=max(res,query(ql,qr,l,m,id<<1)); if(qr>m) res=max(res,query(ql,qr,m+1,r,id<<1|1)); return res; } void pushup(int id) { bit[id]=max(bit[id<<1],bit[id<<1|1]); } void update(int val,int l,int r,int id) { if(l==r) { bit[id]=val; return; } int m=l+(r-l)/2; if(val<=m) update(val,l,m,id<<1); else update(val,m+1,r,id<<1|1); pushup(id); } int main() { int t;cin>>t; while(t--) { int n;scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); last[a[i]]=i; } build(0,n,1); int ans=-inf; for(int i=1;i<=n;i++) { if(last[a[i]]==i) { int l=0,r; while(l<=n) { r=min(n,l+a[i]-1); int temp=query(l,r,0,n,1); ans=max(ans,temp%a[i]); l+=a[i]; } } update(a[i],0,n,1); } printf("%d\n",ans); } return 0; }