HDU 6040 Hints of sd0061(快速排序)

来源:互联网 发布:表格相同时间数据提取 编辑:程序博客网 时间:2024/06/03 12:31

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 aisd0061 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+bjbk is satisfied if bibj, 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(1n107,1m100)

The second line contains m integers, the i-th of which is the number bi of the i-th hint. (0bi<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 #xy1 y2  ym" in one line (without quotes), where x indicates the case number starting from 1 and yi (1im) denotes the rating of noob for the i-th contest of corresponding case.
 

Sample Input
3 3 1 1 10 1 22 2 2 2 21 1
 

Sample Output
Case #1: 1 1 202755Case #2: 405510 405510
 

Source
2017 Multi-University Training Contest - Team 1 
 

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];//查询,查询的idunsigned 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;}

原创粉丝点击