Hints of sd0061
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 520 Accepted Submission(s): 112
Problem Description
sd0061, the legend of Beihang University ACM-ICPC Team, retired last year leaving a group of noobs. Noobs have no idea how to deal with
m
coming contests.
sd0061 has left a set of hints for them.
There are n noobs in the team, the i -th of which has a rating ai . sd0061 prepares one hint for each contest. The hint for the j -th contest is a number bj , which means that the noob with the (bj+1) -th lowest rating is ordained by sd0061 for the j -th contest.
The coach asks constroy to make a list of contestants. constroy looks into these hints and finds out: bi+bj≤bk is satisfied if bi≠bj, bi<bk and bj<bk .
Now, you are in charge of making the list for constroy.
There are n noobs in the team, the i -th of which has a rating ai . sd0061 prepares one hint for each contest. The hint for the j -th contest is a number bj , which means that the noob with the (bj+1) -th lowest rating is ordained by sd0061 for the j -th contest.
The coach asks constroy to make a list of contestants. constroy looks into these hints and finds out: bi+bj≤bk is satisfied if bi≠bj, bi<bk and bj<bk .
Now, you are in charge of making the list for constroy.
Input
There are multiple test cases (about
10
).
For each test case:
The first line contains five integers n,m,A,B,C . (1≤n≤107,1≤m≤100)
The second line contains m integers, the i -th of which is the number bi of the i -th hint. (0≤bi<n)
The n noobs' ratings are obtained by calling following function n times, the i -th result of which is ai .
For each test case:
The first line contains five integers n,m,A,B,C . (1≤n≤107,1≤m≤100)
The second line contains m integers, the i -th of which is the number bi of the i -th hint. (0≤bi<n)
The n noobs' ratings are obtained by calling following function n times, the i -th result of which is ai .
unsigned x = A, y = B, z = C; unsigned rng61() { unsigned t; x ^= x << 16; x ^= x >> 5; x ^= x << 1; t = x; x = y; y = z; z = t ^ x ^ y; return z; }
Output
For each test case, output "
Case #
x
:
y1
y2
⋯
ym
" in one line (without quotes), where
x
indicates the case number starting from
1
and
yi
(1≤i≤m)
denotes the rating of noob for the
i
-th contest of corresponding case.
Sample Input
3 3 1 1 1 0 1 2 2 2 2 2 2 1 1
Sample Output
Case #1: 1 1 202755 Case #2: 405510 405510
Source
Recommend
liuyiding
题目大意:
给你一个长度为N(1<=N<=1e7)的序列的生成方法,有M个查询,每次询问一个数字k,问第k+1大的是数字是哪个。
解题思路:
开始以为可以根据这个生成方法找到一些性质什么的,但是用了不少时间完全没有找到,实际上真的没有性质。
首先从最原始的方法出发,我们可以对这个序列排序,然后直接访问第k+1个元素即可。这样时间复杂度为O(N * log N)显然会TLE。仔细想一下,直接全部排序处理出许多我们不需要知道的信息。查询很少,最多只有100个,但是直接排序得到了所有k大的元素,如果我们能够不处理这些信息就可以减少一些时间复杂度。
回想快速排序的步骤,每次选择一个元素,把比它小的放它前面,比它大的放它后面,这不就是我们要知道的第k的元素吗。快速排序是对所有元素都执行了这个过程,我们只需要其中的m个,也就只需要执行m次这个过程就可了。
对于这个过程的实现,C++ STL中有一个库函数,nth_element。关于它的用法如下:
有了这个函数,我们只需要离线的对查询排序,然后对每个查询的值在不断分割的子区间上调用这个函数(实际上就和快速排序的实现差不多),这样就可有很少冗余度的得到我们所需要的答案。
这样写复杂度的显然是远小于快排的O(N * log N),详细的复杂度计算引用官方题解:
AC代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <string>
#include <map>
#include <set>
#include <list>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define fi first
#define se second
#define mem(a,b) memset((a),(b),sizeof(a))
const int MAXN=10000000+3;
const int MAXM=100+3;
int N,M,A,B,C;
int b[MAXM],pos[MAXM];//查询,查询的id
unsigned a[MAXN],ans[MAXM];//生成的a数组,答案
unsigned x, y, z;
unsigned rng61()
{
unsigned t;
x ^= x << 16;
x ^= x >> 5;
x ^= x << 1;
t = x;
x = y;
y = z;
z = t ^ x ^ y;
return z;
}
inline bool cmp(int x, int y)
{
return b[x]<b[y];
}
int main()
{
int cas=1;
while(~scanf("%d%d%d%d%d",&N,&M,&A,&B,&C))
{
x=A, y=B, z=C;
for(int i=0;i<M;++i)
{
pos[i]=i;
scanf("%d",&b[i]);
}
sort(pos,pos+M,cmp);//把查询排序
pos[M]=M;//加上一个边界,方便判定是否有重复的查询
b[M]=N;
for(int i=0;i<N;++i)//生成序列a
a[i]=rng61();
for(int i=M-1;~i;--i)//由于题目保证bi+bj<=bk所以一定倒着划分最快
{
if(b[pos[i]]==b[pos[i+1]])//如果两个查询的值相同直接复制答案
{
ans[pos[i]]=ans[pos[i+1]];
continue;
}
nth_element(a, a+b[pos[i]], a+b[pos[i+1]]);//进行快排的一部,把第k个元素的元素放到第k个,小的放前面,大的放后面
ans[pos[i]]=a[b[pos[i]]];//保存答案
}
printf("Case #%d:",cas++);
for(int i=0;i<M;++i)
printf(" %u",ans[i]);
putchar('\n');
}
return 0;
}