BZOJ4320 : ShangHai2006 Homework

Claris發表於2015-10-29

取$M=\sqrt{300000}$。

設$g[i]$表示程式設計師的$\bmod i$最小的值。

若$Y<M$,那麼可以在$O(M)$時間內完成對所有$g[i]$的修改,$O(1)$時間內完成查詢。

若$Y\geq M$,那麼列舉$Y$的倍數,等價於查詢一段區間內的最小值,可以通過分塊做到$O(M)$修改,$O(1)$查詢。

因為倍數不超過$M$個,所以詢問的總複雜度為$O(M)$。

所以總時間複雜度為$O(n\sqrt{300000})$。

 

#include<cstdio>
const int N=300010,M=550;
int n=300000,m=n/M,q,i,x,pos[N],st[M],f[N],tag[M],g[M];char op[5];
inline void up(int&a,int b){if(a>b)a=b;}
inline void add(int x){
  for(int i=1;i<M;i++)up(g[i],x%i);
  for(int i=st[pos[x]];i<=x;i++)up(f[i],x);
  for(int i=pos[x]-1;~i;i--)up(tag[i],x);
}
inline int ask(int x){
  if(!x)x++;
  int t=f[x];
  up(t,tag[pos[x]]);
  return t;
}
inline int query(int x){
  if(x<M)return g[x];
  int t=N;
  for(int i=0,j=x;i<=n;i=j,j+=x){
    if(j>n)j=n+1;
    int y=ask(i);
    if(y<j)up(t,y-i);
  }
  return t;
}
int main(){
  for(i=1;i<=n;i++)pos[i]=i/M;
  for(i=n;i;i--)st[pos[i]]=i;
  for(i=1;i<=n;i++)f[i]=N;
  for(i=0;i<=m;i++)tag[i]=N;
  for(i=1;i<M;i++)g[i]=N;
  scanf("%d",&q);
  while(q--){
    scanf("%s%d",op,&x);
    if(op[0]=='A')add(x);else printf("%d\n",query(x));
  }
  return 0;
}