HDU 3303 Harmony Forever 前缀和+树状数组||线段树
Problem Description
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
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
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
Sample Output
题意
让你拯救世界
给定一空集合,有两种操作,往集合里加数或者求出集合中的数在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);
}
}
}
HDU 3303 Harmony Forever 前缀和+树状数组||线段树的更多相关文章
- 树状数组 && 线段树应用 -- 求逆序数
参考:算法学习(二)——树状数组求逆序数 .线段树或树状数组求逆序数(附例题) 应用树状数组 || 线段树求逆序数是一种很巧妙的技巧,这个技巧的关键在于如何把原来单纯的求区间和操作转换为 求小于等于a ...
- hdu1394(枚举/树状数组/线段树单点更新&区间求和)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 ...
- 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树
正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...
- hdu 5147 Sequence II【树状数组/线段树】
Sequence IITime Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem ...
- hdu 1166:敌兵布阵(树状数组 / 线段树,入门练习题)
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- hdu 3966 Aragorn's Story(树链剖分+树状数组/线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意: 给出一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路 ...
- hdu 1166 敌兵布阵——(区间和)树状数组/线段树
pid=1166">here:http://acm.hdu.edu.cn/showproblem.php?pid=1166 Input 第一行一个整数T.表示有T组数据. 每组数据第一 ...
- HDU 1166 敌兵布阵 树状数组||线段树
http://acm.hdu.edu.cn/showproblem.php?pid=1166 题目大意: 给定n个数的区间N<=50000,还有Q个询问(Q<=40000)求区间和. 每个 ...
- Holedox Eating HDU - 4302 2012多校C 二分查找+树状数组/线段树优化
题意 一个长度$n<=1e5$的数轴,$m<=1e5$个操作 有两种一些操作 $0$ $x$ 在$x$放一个食物 $1$ 一个虫子去吃最近的食物,如果有两个食物一样近,不转变方向的去吃 ...
随机推荐
- Twins:眼红红 - fancybot的博客
"我最初面红.现在双眼通红" TWINS 听听歌.小时候.听得最最最多的就是TWINS的了 跳过图片 跳过歌词 眼红红 Twins 仍然怀念他 一起去学结他 一对黑眼圈 回望中三暑 ...
- Microsoft Translator发布粤语文本翻译
今天,Microsoft Translator发布了粤语的文本翻译,新的语言增加将继续丰富微软翻译产品的生态系统*,让更多组织和个人能够快速且高效地实现翻译应用.在中国,大有约5500万人使用粤语(语 ...
- 30s源码刨析系列之函数篇
前言 由浅入深.逐个击破 30SecondsOfCode 中函数系列所有源码片段,带你领略源码之美. 本系列是对名库 30SecondsOfCode 的深入刨析. 本篇是其中的函数篇,可以在极短的时间 ...
- Python学习笔记--threading线程
通过线程来实现多任务并发.提高性能.先看看例子. #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2020-03-02 21:10:39 ...
- 前端每日实战:85# 视频演示如何用纯 CSS 创作一个小球反弹的动画
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/OwWROO 可交互视频 此视频是可 ...
- Access Token 机制详解
我们在访问很多大公司的开放 api 的时候,都会发现这些 api 要求传递一个 access token 参数.这个参数是什么呢?需要去哪里获取这个 access token 呢? access to ...
- docker 升级后启动异常处理
docker升级后启动时提示如下错误: Unable to create at Docker.Core.Pipe.NamedPipeClient.d__5.MoveNext() --- End of ...
- AspNetCore3.1_Middleware源码解析_3_HttpsRedirection
概述 上文提到3.1版本默认没有使用Hsts,但是使用了这个中间件.看名字就很好理解,https跳转,顾名思义,就是跳转到 https地址. 使用场景,当用户使用http访问网站时,自动跳转到http ...
- celery订单定时回滚
目录 订单回滚 控制执行(多少时间后执行) celery异步定时任务 订单回滚 用celery异步,定时任务.可以设置:如果下单15分钟后没有支付,则取消订单.做反向操作 控制执行(多少时间后执行) ...
- 菜鸟对java和Go的理解
1.go对比java go通过结构体嵌套+接口实现类似面向对象中的继承和多态.个人认为尤其是go的接口抓住了多态的本质.而Go提倡的面向接口的思想也可能使得架构上更加解耦. 2.关于Go不要通过共享内 ...