Problem Description

We believe that every inhabitant of this universe eventually will find a way to live together in harmony and peace; that trust, patience, kindness and loyalty will exist between every living being of this earth; people will find a way to appreciate and cooperate with each other instead of continuous bickering, arguing and fighting. Harmony -- the stage of society so many people dream of and yet it seems so far away from now ...
Fortunately, the method of unlocking the key to true Harmony is just
discovered by a group of philosophers. It is recorded on a strange meteorite
which has just hit the earth. You need to decipher the true meaning behind those
seemingly random symbols ... More precisely, you are to write a program which
will support the following two kinds of operation on an initially empty set S
:
1.
B X : Add number X to set S . The Kth command in the form of B X
always happens at time K , and number X does not belong to set S before this
operation.
2.
A Y : Of all the numbers in set S currently, find the one
which has the minimum remainder when divided by Y . In case a tie occurs, you
should choose the one which appeared latest in the input. Report the time when
this element is inserted.
It is said that if the answer can be given in
the minimum possible time, true Harmony can be achieved by human races. You task
is to write a program to help us.

Input

There are multiple test cases in the input file. Each
test case starts with one integer T where 1<=T<=40000 . The following T
lines each describe an operation, either in the form of ``B X " or ``A Y " where
1<=X , Y<=500000 .

T = 0 indicates the end of input file and should
not be processed by your program.

Output

Print the result of each test case in the format as
indicated in the sample output. For every line in the form of ``A Y ", you
should output one number, the requested number, on a new line; output -1 if no
such number can be found. Separate the results of two successive inputs with one
single blank line.

Sample Input

5
B 1
A 5
B 10
A 5
A 40
2
B 1
A 2
0

Sample Output

Case 1:
1
2
1
Case 2:
1
 

题意

  让你拯救世界

  给定一空集合,有两种操作,往集合里加数或者求出集合中的数在mod k意义下最小值是第几个加入的,相等的话输出最后加入的

分析

  不管怎么样先想一个暴力吧,单开一个数组记录往里边加的数,下边i表示加入时间,每次查询遍历一遍数组就行

 

 #include<cstdio>
const int N=1e5+;
int a[N];
int main(){
char ss[];
int num,t,cas=;
while(~scanf("%d",&t)){
int len=;
if(t==)return ;
if(cas)printf("\n");
printf("Case %d:\n",++cas);
while(t--){
scanf("%s%d",ss,&num);
if(ss[]=='B')
a[++len]=num;
else {
bool flag=;
int Min=num,ans;
for(int i=;i<=len;i++){
if(a[i]%num<=Min){
flag=;
Min=a[i]%num;
ans=i;
}
}
if(flag)printf("-1\n");
else printf("%d\n",ans);
}
}
}
}

  抱着试一试的心态交了上去,A了!!!没错它A了,但显然这不是正解,只是HDU数据水了,我自己手造了一组极限数据就跑了2s多,然后我又把它交到了POJ上,果然是TLE。

  那肯定是要优化咯,怎么优化呢?涉及到mod的问题,如果要mod k在连续长度大于k的区间中,mod k一定会至少有两个数相等,所以我们可以考虑将50w分块,分为0-k-1,k-2k-1…………这样遍历每一块,每一块中最小的数mod k就有可能是答案,于是这个问题就成了,在区间内找到最小的已经出现过的数字,涉及到区间问题,很容易想到线段树和树状数组,但这个问题好像没有必要用线段树,树状数组足以。

  开一棵50w的树状数组,每一个点记录到这个点一共出现了多少数字,接着就是找最小的已经出现过的数,那么不就又是暴力了吗?查找的方法除了暴力就只会二分,于是我们考虑二分查找,怎么二分呢?每次查找区间的时候,对该区间进行二分就行了,那你怎么知道是要向左分还是向右分?用树状数组很容易求得到区间左端点的点总数,取mid,如果到mid的点总数和到左端的点总数相等,说明l到mid之间没有数,改变左端点,如果有就改变右端点,更新最小值,继续二分直到l==r,树状数组的做法就是这样,线段树也大致差不多。

   还有一个问题,如果k过小了,比如k就是1,那么我们就会将区间分成50w块,50w啊!而暴力最多只枚举4w,所以我们可以设置一个值,让k过大的时候直接用暴力。

  

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int limit=;//这个数还可以换,让它别太小就行
//不要问我为什么非用这个奇怪的数
const int N=5e5+;
int q[N+],tim[N+],a[N+],len,c[N+];//多开5,防止RE
int lowbit(int i){
return i&(-i);
}
void Add(int x){
while(x<=N){
c[x]++;
x+=lowbit(x);
}
}
int n,k;
void Ins(int x){
tim[++len]=x;
a[x]=len;
for(int i=;i<=limit;i++){
if(q[i]==)q[i]=len;
else if(x%i<=tim[q[i]]%i)q[i]=len;//等于也要替换,因为优先输出后读入的
}
Add(x);//加到树状数组里统计前缀和
}
int front_sum(int x){
int sum=;
while(x){
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
int low_find(int ll,int rr){
int l,r,Min=;
if(ll==)l=;
else l=ll;
if(rr>N)r=N;
else r=rr;
int pre=front_sum(l-);
while(l<=r){
int mid=l+r>>;
int now=front_sum(mid);
if(now>pre){//说明mid到l之间出现了值,向左找
r=mid-;
Min=mid;
}else l=mid+;//没有值就向右找
}
return Min;
}
void calc(int x){
if(len==){printf("-1\n");return;}
if(x<=limit){printf("%d\n",q[x]);return;}
int l=,r=x-,ans=x-;
while(l<=N){//判断左边界,判断右边界的话取值可能不完全
int now=low_find(l,r);
if(now&&(now%x<ans%x||now%x==ans%x&&a[now]>a[ans])){
//等于和小于两种情况分开写,合在一起不行
ans=now;
}
l+=x;r+=x;
}
printf("%d\n",a[ans]);
}
int main(){
int cas=;
while(~scanf("%d",&n)){
if(n==)return ;
for(int i=;i<=N;i++){
tim[i]=a[i]=c[i]=q[i]=;
}
len=;
if(cas)printf("\n");
printf("Case %d:\n",++cas);
for(int i=;i<=n;i++){
char ss[];
scanf("%s%d",ss,&k);
if(ss[]=='A')calc(k);
else Ins(k);
}
}
}

最新文章

  1. JAVA hashmap知识整理
  2. 黄聪:GeckoWebBrowser多窗口独立cookie
  3. c语言,检测一个无符号整数中是否有偶数位个1
  4. 使用AlarmManager设置闹钟----之二
  5. KVC - 键值编码
  6. JAVA多线程--Thinking in java
  7. linux mysql 修改 UTF-8编码
  8. socket.io笔记
  9. 第五十六 css选择器和盒模型
  10. hibernate源码分析1
  11. hql和sql练习题
  12. 第5月第7天 php slim
  13. python基础入门--input标签、变量、数字类型、列表、字符串、字典、索引值、bool值、占位符格式输出
  14. Map的isEmpty()与==null的区别
  15. angularjs -- 页面模板清除
  16. Java如何比较两个数组?
  17. MyISAM压缩表
  18. 材料设计---Design
  19. 使用servlet3.0提供的API来进行文件的上传操作
  20. Git学习笔记(SourceTree克隆、提交、推送、拉取等)

热门文章

  1. flutter 入门(Mac)
  2. android使用giflib加载gif
  3. 极验验证码破解之selenium
  4. 【原创】从零开始搭建Electron+Vue+Webpack项目框架(五)预加载和Electron自动更新
  5. Flutter跨平台框架的使用-iOS最新版
  6. 小程序在ios10.2系统上兼容
  7. 【视频+图文】带你快速掌握带continue语句的双重for循环
  8. Enbale IE mode in Edge
  9. Windows 使用激活服务器激活操作步骤
  10. 从web现状谈及前端性能优化