题意:
给你一个长度为n的序列,序列由题面给的函数生成。然后m次询问,询问这个序列上第bi小的数。
分析:
n最大达到1e7,单纯的快排是不行的。但是可以利用快排的思想,每次找到一个划分,序列中比划分值小的数都在划分的左侧,反之则在右侧,这样每阶段都可以省一段时间。题面给的函数返回类型是unsigned,这个也需要注意。
这就需要一个利器的STL了,C++中的nth_element(arr,arr+k,arr+n),用法是将长度为n的数组arr进行划分,第k位置上就是第k+1大的数(下标从0开始算,也即有k个数比arr[k]小),最重要的是这个函数近似线性!!!
注意:
因为输入保证任意两个小的之和小于第三个
所以查询数列的间隔一定大于等于斐波那契
也就是从大到小查询的话,每次至少能去掉一半的区间
#include <bits/stdc++.h>
#define test TEST
using namespace std;
typedef long long ll;
const int maxn=1e7+7;
int b[105],id[105];
unsigned ans[105];
bool vis[maxn];
unsigned a[maxn];
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;
}
bool cmp(const int &xx,const int &yy){
return b[xx]>b[yy];
}
int main(int argc, char const *argv[])
{
ll n,m;
int cas=1;
while(~scanf("%lld %lld %u %u %u",&n,&m,&x,&y,&z)){
memset(vis,0,sizeof(vis));
for(int i=0;i<m;i++){
scanf("%d",&b[i]);
id[i]=i;
}
for(int i=0;i<n;i++){
a[i]=rng61();
}
sort(id,id+m,cmp);//挑选询问大的编号放在前面,可以降低复杂度
int p,last=n;
for(int i=0;i<m;i++){
p=id[i];
nth_element(a,a+b[p],a+last);
ans[p]=a[b[p]];
last=b[p];
}
//输出答案
printf("Case #%d:",cas++);
for(int i=0;i<m;i++){
printf(" %u",ans[i]);
}printf("\n");
}
return 0;
}