您的位置:首页 > 其它

HDU-2017 多校训练赛1-1008-Hints of sd0061

2017-07-27 04:42 543 查看
ACM模版

描述



题解

做这个题真是长见识了,由于序列比较大并且需要生成序列,所以直接快排时间会超,那么怎么做呢?自然是寻求近似线性复杂度的解法了。

官方题解是这么说的:

最慢的情况是  $b$ 的取值为 $0, 1, 2, 3, 5, 8, …$ 的情况,但事实上也只有 $\mathcal{O}(\log_{1.618}{n})$ 个取值。

从最大的取值到最小的取值依次使用近似线性复杂度的求第 $k$ 小的方法即可,该方法的思想与快排相似,可以保证前 $k - 1$ 小的元素都放置在第 $k$ 小元素的前面,这样枚举的时候就可以依次减少每次的枚举量,时间复杂度 $\displaystyle\mathcal{O}\left(\sum_{i \geq 0}{\frac{n}{1.618^i}}\right) = \mathcal{O}(n)$ 。


这里,用到了一个 STL 函数,很牛逼的一个东西,之前就没有用过,看见标程里用到了,感觉简单快捷,所以找了找这个函数的介绍。

nth_element(a, a + x, a + n);
//  将在 [0 ~ n) 区间的第 x + 1 大的数放置在 x 处,
//  小于它的 x 个数放在前边,其余的放后边,无序


这个函数的内部算法和上述的算法相似,时间复杂度也是近似线性的,没毛病。

代码

#include <cstdio>
#include <algorithm>

using namespace std;

const int MAXN = 1e7 + 10;
const int MAXM = 111;

int n, m;
unsigned a[MAXN];
unsigned c[MAXM];

struct xxx
{
int val, pos;

bool operator < (const xxx y) const
{
return val < y.val;
}
} b[MAXM];

unsigned x, y, z;
inline 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;
}

int main()
{
int ce = 1;
while (~scanf("%d%d%u%u%u", &n, &m, &x, &y, &z))
{
for (int i = 0; i < m; ++i)
{
scanf("%d", &b[i].val);
b[i].pos = i;
}
sort(b, b + m);

for (int i = 0; i < n; ++i)
{
a[i] = rng61();
}

b[m].val = n;
for (int i = m - 1; ~i; --i)
{
nth_element(a, a + b[i].val, a + b[i + 1].val);
c[b[i].pos] = a[b[i].val];
}

printf("Case #%d: ", ce++);
for (int i = 0; i < m - 1; ++i)
{
printf("%u ", c[i]);
}
printf("%u\n", c[m - 1]);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  STL