BZOJ4320 : ShangHai2006 Homework

取$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;
}

  

posted @ 2015-10-29 23:48  Claris  阅读(875)  评论(0编辑  收藏  举报