题意:
给定一串数字 a 与若干次询问 x(通过 b 数组给出),每次输出 a 中的 第 (x+1) 小数字
学了一招 nth_element,
nth_element
is a partial sorting algorithm that rearranges elements in [first, last)
such that:
- The element pointed at by
nth
is changed to whatever element would occur in that position if[first, last)
was sorted. - All of the elements before this new
nth
element are less than or equal to the elements after the newnth
element.
——cppreference.com
// 说是效果近似线性0 0
因为 a 数组本身的特性,从大往小找是效率最高的。而且每次找完了大的,后面那段就可以直接扔掉,下次查找就以这次找到的位置作为结尾。
因此,考虑先将 b 数组从大到小排序。这里又学了一招,可以用 id[i] = i, 然后排序 id 数组,cmp 写作
bool cmp(int u, int v) { return b[u] > b[v]; }
这样做起来感觉比结构体数组排序然后折腾啥的要清楚一点...(。
另一个注意点就是对于相同的询问可以直接继承上一次的答案(因为排过序后就靠在一起了),没必要再去查找。
Code:
#include <bits/stdc++.h>
#define maxn 10000010
unsigned x, y, z, rat[maxn], ans[maxn], A, B, C;
int n, m, b[110], id[110], kas;
using namespace std;
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(int u, int v) { return b[u] > b[v]; }
void work() {
x = A; y = B; z = C;
for (int i = 0; i < n; ++i) rat[i] = rng61();
for (int i = 0; i < m; ++i) { scanf("%d", &b[i]); id[i] = i; }
sort(id, id + m, cmp);
int en = n;
for (int i = 0; i < m; ++i) {
if (i > 0 && b[id[i]] == b[id[i - 1]]) {
ans[id[i]] = ans[id[i - 1]];
continue;
}
nth_element(rat, rat + b[id[i]], rat + en);
ans[id[i]] = rat[b[id[i]]];
en = b[id[i]];
}
printf("Case #%d: %u", ++kas, ans[0]);
for (int i = 1; i < m; ++i) printf(" %u", ans[i]); printf("\n");
}
int main() {
while (scanf("%d%d%u%u%u", &n, &m, &A, &B, &C) != EOF) work();
return 0;
}