hdu 3303 Harmony Forever (线段树 + 抽屉原理)

时间:2023-05-29 23:18:50

http://acm.hdu.edu.cn/showproblem.php?pid=3303

Harmony Forever

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 813    Accepted Submission(s): 222

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
Sample Output
Case 1:
1
2
1
Case 2:
1
Source

题解:

很显然的线段树问题,但是这个题有点技巧就是利用抽屉原理来降低复杂度。

什么是抽屉原理?抽屉原理也叫鸽巢原理,鸽巢原理就是给定N+1个数,则必定至少有两个数Mod(N)的余数是相同的! 假设要求的MOD是Y,则首先查找[0,Y-1]区间的最小值,因为这样的区间不会有两个数的余数相同,记录下结果。然后依次查找[Y,Y+Y-1],[Y+Y,Y+Y+Y-1]。。。。等区间,每个区间都会找出一个最小值,将这些最小值对Y进行取模,得到最小值!

这题还要注意:范围较小的时候直接查找,否则TLE。

代码:

 #include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector> using namespace std;
#define N 500000
#define INF 100000000
vector<int> vct; struct Nod
{
int l,r,mins;
}node[(N<<)+]; int maxInput;
int posArray[N+]; void building(int l,int r,int p)
{
node[p].l = l;
node[p].r = r;
node[p].mins = INF;
if(l==r) return ;
int mid = (l+r)>>;
building(l,mid,p<<);
building(mid+,r,p<<|);
} void update(int x,int p)
{
if(node[p].l>x||node[p].r<x) return;
if(node[p].l == node[p].r&&node[p].l==x)
{
node[p].mins = x;
return;
}
update(x,p<<);
update(x,p<<|);
node[p].mins = min(node[p<<].mins,node[p<<|].mins);
}
/**RE的查询方式 int query(int l,int r,int p) //找[l,r]区间的最小值
{
if(node[p].l == l && node[p].r == r) return node[p].mins;
int mid = (node[p].l+node[p].r)>>1;
if(r<=mid) return query(l,r,p<<1);
else if(mid>l) return query(l,r,p<<1|1);
else return min(query(l,mid,p<<1),query(mid+1,r,p<<1|1));
} */
int Query(int l,int r,int index)//找[l,r]区间的最小值
{
if(node[index].l>r || node[index].r<l) return INF;
if(node[index].l>=l && node[index].r<=r) return node[index].mins;
if(node[index].l < node[index].r)
return min(Query(l,r,index<<),Query(l,r,index<<|));
return INF;
} int search(int y)
{
int minAns = INF,id = ,i;
for(i=vct.size()-;i>=;i--)
{
if(vct[i]%y== ) return i+;
if(vct[i]%y<minAns)
{
minAns = vct[i]%y;
id = i+;
}
}
return id;
} int solve(int y) //抽屉原理
{
int l=,r=y-,minAns=INF,id,temp;
while(l<=maxInput)
{
if(maxInput<r) r=N;
temp = Query(l,r,);
if(temp!=INF)
{
if(temp%y<minAns)
{
minAns = temp%y;
id = posArray[temp];
}
else if(temp%y == minAns && posArray[temp] > id)
{
id = posArray[temp];
}
}
l+=y;
r+=y;
}
return id;
} int main()
{
int t,cas=;
while(~scanf("%d",&t)&&t)
{
building(,N,);
char op[];
maxInput = ;
vct.clear();
if(cas!=) printf("\n");
printf("Case %d:\n",cas++);
while(t--)
{
scanf("%s",op);
if(op[]=='B')
{
int x;
scanf("%d",&x);
if(maxInput<x) maxInput = x;
vct.push_back(x);
posArray[x] = vct.size();
update(x,);
}
else if(op[]=='A')
{
int y;
scanf("%d",&y);
if(vct.size()==) puts("-1");
else if(y<=) printf("%d\n",search(y)); //防超时
else printf("%d\n",solve(y));
}
}
}
return ;
}