每次正好中分。
因为这样才严格地进行了分而治之,则完美用到了二分的时间复杂度
反之,如果每次都选到了边缘,则每次递归处理的序列大小为
观察程序显而易见。
A[]={46, 23, 8, 99, 31, 12, 85}
1, 0, 2, 3, 5, 4, 6
实际上就是对索引排序,然后所谓非递归的归并排序执行第1趟
就是(0,1) (1,2) ...
这些互换位置。
A[]={23, 46, 8, 99, 31, 12, 85}
2, 5, 0, 4, 1, 6, 3
- A.希尔排序
- B.堆排序
- C.归并排序(对)
- D.快速排序
- A.堆排序
- B.插入排序(对)
- C.冒泡排序
- D.快速排序
有可能最后一个元素插到最前面,所有元素后移。
- A.快速排序
- B.直接插入
- C.选择排序(对)
- D.堆排序
选择排序咋都得来个
- A.冒泡排序(后2个数必须是最大的)
- B.插入排序(前2个数必须是有序的)
- C.选择排序(前2个数必须是最小的)
- D.快速排序(至少
1+2
个元素在正确的位置上)
2 3 4 6 8 9 11 20
3 2 4 9 8 11 6 20
√ √ √
这个快排问题在哪?
额外的空间就不是
A. 归并排序 B. 快速排序 C. 堆排序 D. 选择排序
答案是C。但是这个答案真的对吗?
摘自曾纪岚:感觉优化过的选择排序或许会更好,将选择排序中的maxdate换成一个数组形式,可以用最小堆进行存储。每次把读入数据和堆顶进行比较,然后删除,插入即可。(没太懂)
摘自mooc41747005296524519:如果只有这四个选项,我会选堆排序;但我觉得冒泡排序性能可能会更好
给定公司 N 名员工的工龄,要求按工龄增序输出每个工龄段有多少员工。
输入格式:
- 输入首先给出正整 N(≤$10^5$),即员工总人数;随后给出 N 个整数,即每个员工的工龄,范围在
$[0, 50]$ 。
输出格式:
- 按工龄的递增顺序输出每个工龄的员工个数,格式为:“
工龄:人数
”。每项占一行。如果人数为 0 则不输出该项。
输入样例:
8
10 2 0 5 7 2 5 2
输出样例:
0:1
2:3
5:2
7:1
10:1
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<int, int> hash;
int n;
cin >> n;
for (int i = 0; i < n; ++ i)
{
int a;
cin >> a;
hash[a] ++ ;
}
for (auto&& item: hash)
printf("%d:%d\n", item.first, item.second);
}
参考我的算法笔记:https://github.com/PiperLiu/ACMOI_Journey
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>
using namespace std;
const int K = 6;
int n, k, m;
int p_score[K];
struct Student
{
string id;
int grade[K];
int total, cnt; // 总分 与 完美完成题目数量
Student(){}
Student(string _id) : id(_id)
{
// 初始化, -2 代表从来没有提交过
for (int i = 1; i <= k; i ++ ) grade[i] = -2;
total = cnt = 0;
}
void calc()
{
for (int i = 1; i <= k; i ++ )
{
total += max(0, grade[i]);
if (grade[i] == p_score[i]) cnt ++ ;
}
}
bool has_submit()
{
for (int i = 1; i <= k; i ++ )
if (grade[i] >= 0)
return true;
return false;
}
// 重载 < 为数值的 > 用于从大到小排
bool operator< (const Student& t) const
{
if (total != t.total) return total > t.total;
if (cnt != t.cnt) return cnt > t.cnt;
return id < t.id; // 注意 id 是字典序升序
}
};
int main()
{
unordered_map<string, Student> students;
scanf("%d%d%d", &n, &k, &m);
for (int i = 1; i <= k; i ++ ) scanf("%d", &p_score[i]);
while (m -- )
{
string u_id;
char u_id_s[6];
int p_id, grade;
scanf("%s%d%d", u_id_s, &p_id, &grade);
u_id = u_id_s;
if (students.count(u_id) == 0) students[u_id] = Student(u_id);
students[u_id].grade[p_id] = max(students[u_id].grade[p_id], grade);
}
vector<Student> res;
for (auto& item: students)
{
auto& s = item.second;
if (s.has_submit())
{
s.calc();
res.push_back(s);
}
}
sort(res.begin(), res.end());
// total 相同则 rank 相同
for (int i = 0, rank = 1; i < res.size(); i ++ )
{
if (i && res[i].total != res[i - 1].total) rank = i + 1;
printf("%d %s %d", rank, res[i].id.c_str(), res[i].total);
for (int j = 1; j <= k; j ++ )
if (res[i].grade[j] == -2) printf(" -");
else printf(" %d", max(0, res[i].grade[j]));
puts("");
}
return 0;
}
参考我的算法笔记:https://github.com/PiperLiu/ACMOI_Journey
// 转换为图论问题,如图, i 在 p[i] 位置上,则 i 指向 p[i]
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int n;
int p[N];
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ )
{
int id;
scanf("%d", &id);
p[id] = i;
}
int res = 0;
for (int i = 1; i < n;)
{
while (p[0]) swap(p[0], p[p[0]]), res ++ ; // p[0] 不指向 0 ,把环上点变为自环
while (i < n && p[i] == i) i ++ ; // 找下一个不是自环的环
if (i < n) swap(p[0], p[i]), res ++ ; // 让 0 进入该环
}
printf("%d\n", res);
return 0;
}