題面連接:https://www.lydsy.com/JudgeOnline/problem.php?id=4320
令M=sqrt(mx),把詢問的Y按
一、對於>M的Y,咱們發現它的倍數不超過M個,因而能夠枚舉倍數,找到日後第一個已經被加入集合的值,用差值更新答案。
這個東西咱們能夠離線,倒序枚舉詢問,而後用並查集維護。
單次查詢O(M),更新O(1).
二、對於<M的Y,倍數確定是>M,不過這樣的Y也就M個,能夠直接拿數組存,g[i]表示目前%i最小爲多少(即答案),更新的時候直接遍歷M個位置取min便可。
單次查詢O(1),更新O(M).
因此總時間複雜度爲O(n*sqrt(n))的。
#include<bits/stdc++.h> using namespace std; const int N = 300005; #define rep(i,a,b) for(register int i=(a);i<=(b);++i) #define dwn(i,a,b) for(register int i=(a);i>=(b);--i) typedef long long ll; int n,X[N],Y[N],ans[N],fa[N],g[N],kua,mx,mn; bool vis[N]; char s[2]; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} int main(){ memset(ans,-1,sizeof(ans)); scanf("%d",&n); rep(i,1,n){ scanf("%s%d",s,&Y[i]); if(s[0]=='A')X[i]=1,vis[Y[i]]=1; else X[i]=2; mx=max(mx,Y[i]); } kua=sqrt(mx)+1; rep(i,0,mx+1)fa[i]=i; dwn(i,mx,0){ if(vis[i])continue; fa[find(i)]=find(i+1); } memset(g,0x3f,sizeof(g)); rep(i,1,n){ if(X[i]==1){ rep(j,1,kua){ g[j]=min(g[j],Y[i]%j); } } else if(Y[i]<=kua)ans[i]=g[Y[i]]; } dwn(i,n,1){ if(X[i]==1){ fa[find(Y[i])]=find(Y[i]+1); } else if(Y[i]>kua){ mn=1e9; for(int j=0;j<=mx;j+=Y[i]){ if(find(j)>mx)continue; mn=min(mn,find(j)-j); } ans[i]=mn; } } rep(i,1,n)if(~ans[i])printf("%d\n",ans[i]); return 0; }