【题解】[JLOI2011]不重复数字
题目
题目来源:CCF 吉林省选 2011;
在线评测地址:Luogu#4305;
运行限制:时间 \(1.00\ \textrm{s}\),空间 \(128\ \textrm{MiB}\)。
题目描述
给定 \(n\) 个数,要求把其中重复的去掉,只保留第一次出现的数。
输入格式
本题有多组数据。
第一行一个整数 \(T\),表示数据组数。
对于每组数据:
第一行一个整数 \(n\)。
第二行 \(n\) 个数,表示给定的数。
输出格式
对于每组数据,输出一行,为去重后剩下的数,两个数之间用一个空格隔开。
数据规模及约定
- 对于 \(30\%\) 的数据,\(n\le 100\),给出的数 \(\in [0, 100]\)。
- 对于 \(60\%\) 的数据,\(n\le 10^4\),给出的数 \(\in [0, 10^4]\)。
- 对于 \(100\%\) 的数据,\(1\le T\le 50\),\(1\le n\le 5 \times 10^4\),给出的数在 \(32\) 位有符号整数范围内。
分析
题意很明确,问题就是怎么解决。我们要实现两个操作,即:
- 询问一个数是否在集合内;
- 将一个数插入集合中。
\(60\ \texttt{pts}\)
我们可以用 set,复杂度是 \(\mathcal{O}(T\sum (n\log n))\),带入极限数据大约是 \(50\times 5\times 10^4\times 16=4\times 10^7\),由于平衡树常数大会被卡常而无法通过。
\(100\ \texttt{pts}\)
Solution 1
这时,我们会想到用哈希表。哈希表的均摊复杂度是 \(\mathcal{O}(T\sum n)\),可以轻松通过这题。
但是一般的哈希表会被卡,又不想写多模数,那么怎么办呢?unordered_set 闪亮登场。
这是 C++11 新增的一个数据结构,对应着一个哈希表。有着官方加持的哈希表跑得飞快,吸氧以后就能过了。
Solution 2
当然,我们还有另一种方法——离散化。
但是,一般的排序算法的极限复杂度就是 \(\mathcal{O}(n\log n)\),依旧会被卡(但是比平衡树好很多)。但是如果用基数排序呢?
单次排序的复杂度就是 \(\mathcal{O}(n\log_{10} x)\),可以比较高效,实际性能待检测。
Code
用了第一种做法,在洛谷少爷机上最慢跑了 \(900\ \textrm{ms}\) 左右,很悬。正解应该还是 Hash。
#include <cstdio>
#include <unordered_set>
using namespace std;
unordered_set<int> st;
int main()
{
int cas, n, tmp;
scanf("%d", &cas);
while (cas--)
{
st.clear();
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &tmp);
if (st.find(tmp) == st.end())
{
printf("%d ", tmp);
st.insert(tmp);
}
}
putchar('\n');
}
return 0;
}
本文来自博客园,作者 5ab,转载请注明链接哦 qwq
博客迁移啦,来看看新博客吧 -> https://5ab-juruo.oier.space/