HDU 3303 Harmony Forever
题意: 现有一个空的集合,有连续的 m 组操作
B x 将 x 加入集合
A x 询问集合中的元素 y % x 的取得最小值的 y
分析: 鸽巢定理+线段树
然后对每个y,由鸽巢定理,连续的y+1个数中必然存在mod y相同的数,可以多区间查询,
即[0, y - 1] [y , 2 * y - 1] 取最优解
当y比较小的时候,直接遍历会更快,即当 y<log(n) 的时候采用遍历的方法
由于数据比较少,可以先进行离散化来提高效率。
#include<stdio.h> #include<string.h> #define clr(x)memset(x,0,sizeof(x)) #define INF 0x1f1f1f1f #define maxn 510005 #define min(a,b)(a)<(b)?(a):(b) #define max(a,b)(a)>(b)?(a):(b) int mi[maxn<<2]; int pos[maxn]; int res[maxn]; void update(int c,int l,int r,int rt) { if(l==r) { mi[rt]=c; return; } int mid=(l+r)>>1; if(c<=mid) update(c,l,mid,rt<<1); else update(c,mid+1,r,rt<<1|1); mi[rt]=min(mi[rt<<1],mi[rt<<1|1]); } int ans; void query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { ans=min(ans,mi[rt]); return; } int mid=(l+r)>>1; if(L<=mid) query(L,R,l,mid,rt<<1); if(R>mid) query(L,R,mid+1,r,rt<<1|1); } int main() { int m,top,tmp,tt,ll,rr,x,i,ca=1,re; char op[2]; while(scanf("%d",&m)!=EOF) { if(m==0) break; if(ca!=1) printf("\n"); printf("Case %d:\n",ca++); memset(pos,-1,sizeof(pos)); memset(mi,INF,sizeof(mi)); top=0; while(m--) { scanf("%s%d",op,&x); if(op[0]=='B') { if(pos[x]==-1) { pos[x]=top; res[top++]=x; update(x,1,maxn-1,1); } } else { if(x<5000) { ans=INF; tmp=x; for(i=top-1;i>=0;i--) { if(res[i]%x<tmp) { tmp=res[i]%x; ans=res[i]; } if(tmp==0) break; } if(ans==INF) printf("-1\n"); else printf("%d\n",pos[ans]+1); } else { tt=500010/x; re=INF; tmp=x; for(i=0;i<=tt;i++) { ans=INF; ll=i*x; ll=max(ll,1); rr=(i+1)*x-1; rr=min(rr,500009); query(ll,rr,1,maxn-1,1); if(ans==INF) continue; if(ans%x<tmp) { tmp=ans%x; re=ans; } else if(ans%x==tmp) { if(pos[ans]>pos[re]) re=ans; } } if(re==INF) printf("-1\n"); else printf("%d\n",pos[re]+1); } } } } return 0; }