0x05 基本算法-排序
A题:Cinema
经典离散化例题,把电影的语言与字幕和观众懂的语言放进一个数组,然后离散化。
最后统计快乐人数。
const int N = 200006;
int n, m, a[N], x[N], y[N], cinema[N * 3], tot = 0, k, ans[N * 3];
int find(int f) { return lower_bound(cinema + 1, cinema + k + 1, f) - cinema; }
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i], cinema[++tot] = a[i];
cin >> m;
for (int i = 1; i <= m; ++i) cin >> x[i], cinema[++tot] = x[i];
for (int i = 1; i <= m; ++i) cin >> y[i], cinema[++tot] = y[i];
sort(cinema + 1, cinema + tot + 1);
k = unique(cinema + 1, cinema + tot + 1) - (cinema + 1);
memset(ans, 0, sizeof(ans));
for (int i = 1; i <= n; i++) ans[find(a[i])]++;
int ans0 = 1, ans1 = 0, ans2 = 0;
for (int i = 1; i <= m; i++) {
int ansx = ans[find(x[i])], ansy = ans[find(y[i])];
if (ansx > ans1 || (ansx == ans1 && ansy > ans2)) {
ans0 = i;
ans1 = ansx;
ans2 = ansy;
}
}
cout << ans0 << endl;
return 0;
}
当然不用离散化也可以做。
简单使用 unordered_map 映射个数即可
const int N = 2e5 + 10;
int _, n, x, y, tmp, a[N];
unordered_map<int, int> mp;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
for (cin >> _; _--;) cin >> tmp, mp[tmp]++;
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= n; ++i) {
int t;
cin >> t;
if (mp[a[i]] > x)
tmp = i, x = mp[a[i]], y = mp[t];
else if (mp[a[i]] == x && mp[t] > y)
tmp = i, y = mp[t];
}
cout << tmp << "\n";
return 0;
}
B题:货仓选址
排序一下,利用中位数的性质
int n, ans, sum;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
cin >> n;
vector<int> v(n);
for (auto &t : v) cin >> t;
sort(v.begin(), v.end());
ans = v[n / 2];
for (auto &t : v) sum += abs(t - ans);
cout << sum << "\n";
return 0;
}
C题:七夕祭
这里借下 洛凌璃dalao的blog题解
题解
这个题其实是两个问题:
1.让摊点上下移动,使得每行的摊点一样多
2.左右移动摊点,使得每列的摊点一样多
两个问题是等价的,就讨论第一个
r[i]表示每行的摊点数
然后使得r[i]的一些摊点移动到r[i - 1]和r[i + 1], 类似于"均摊纸牌"
均摊纸牌
有M个人排一排,每个人分别有C[1]~C[M]张拍,每一步中,一个人可以将自己的一张手牌给相邻的人,求至少需要几步
显然, 纸牌总数T能被M整除有解,在有解的情况下, 考虑第一个人:
1.C[1] >= T/M, 第一个人要给第二个人C[1] - T/M张牌
2.C[1] < T/M, 第二个给第一个人T/M - C[1]张牌
本质就是使得第一人满足要求要|T/M - C[1]|步
那么满足第二人就要 |T/M - (C[2] - (T/M - C[1]))| = |2 * T/M - (C[1] + C[2])|步
满足第三人 |T/M - (C[3] - (T/M - (C[2] - (T/M - C[1]))))| = |3 * T/M - (C[1] + C[2] + C[3])|
到这里就可以发现,有一段是前缀和, 但再仔细化简以下可以发现
|3 * T/M - (C[1] + C[2] + C[3])|
=|(T/M - C[1]) + (T/M - C[2]) + (T/M - C[3])|
=|(C[1] - T/M) + (C[2] - T/M) + (C[3] - T/M)|
我们可以让A[i] = C[i] - T/M, S[i]为A[i]的前缀和,
那么对于"均摊纸牌"这道题的答案就是
∑ni=1∑i=1n|S[i]|
对于本题来说,无非是变成了环形问题
直接无脑dp就可以
我们随便选取一个人k最为断环的最后一名(即第一个人变为为k + 1),
则从这个人开始的持有的牌数(这行的摊点数), 前缀和为
A[k + 1] S[k + 1] - S[k]
A[k + 2] S[k + 2] - S[k]
...
A[M] S[M] - S[k]
A[1] S[M] - S[k] + S[1]
A[2] S[M] - S[k] + S[2]
...
A[k] S[M] - S[k] + S[k]
我们发现S[M] = 0, 所以答案为
|S[k + 1] - S[k]| + ... + |S[M] - S[k]| + |s[M] - S[k] + S[1]| + ... + |S[M] - S[K] + S[k]|
=|S[k + 1] - S[k]| + ... + |S[M] - S[k]| + |-S[k] + S[1]| + ... + |-S[k] + S[k]|
=∑ni=1∑i=1n |S[i] - S[k]|
答案已经很明显了,像不像"仓货选址"?
仓货选址
一条轴上有N家店,每家店的坐标为D[1]~D[N],选择一家点为仓库向其他商店发货,求选哪家店,运送距离最短
不就是∑ni=1∑i=1n |D[i] - D[k]| 为答案吗?
当然是选中位数了啦,
设k左边有P家店,右边有Q家店
如果P<Q,那必然将k右移, ans - Q + P,答案明显变小了
Q>P,同理,故选择中位数
所以本题的答案就已经近在眼前了, 前缀和,求中位数
using ll = long long;
const int maxn = 1e5 + 5;
int n, m, k;
int c[maxn], r[maxn], s[maxn];
ll work(int a[], int n) {
for (int i = 1; i <= n; ++i) s[i] = s[i - 1] + a[i] - k / n;
sort(s + 1, s + 1 + n);
ll ans = 0;
for (int i = 1; i <= n; ++i) ans += abs(s[i] - s[(n >> 1) + 1]);
return ans;
}
int main() {
cin >> n >> m >> k;
for (int i = 1; i <= k; ++i) {
int a, b;
cin >> a >> b, ++c[b], ++r[a];
}
if (k % n + k % m == 0)
cout << "both " << work(c, m) + work(r, n);
else if (k % n == 0)
cout << "row " << work(r, n);
else if (k % m == 0)
cout << "column " << work(c, m);
else
cout << "impossible";
return 0;
}
【例题】Running Median (对顶堆)
题意:动态的维护中位数的问题,依次读入一个整数,每当总个数为奇数时输出此时序列的中位数
使用对顶堆的在线做法。
为了实时找到中位数,我们可以建议两个二叉堆:一个小根堆、一个大根堆。在依次读入数字的过程设当前序列长度为 \(M\),我们始终保持:
- 序列中从小到大排名为 \(1\) ~ $ M/2 $ 的整数存储在大根堆中;
- 序列中从小到大排名为 \(M/2 + 1\) ~ \(M\) 的整数存储在小根堆中。
任何时候如果某一个堆中元素过多则是打破了平衡需要取出该堆的堆顶插入到另一个堆。这样一来序列的中位数就是小根堆的堆顶
关于新数 \(X\) 插入:如果 \(X\) 比中位数小,则插入大根堆,否则就插入小根堆。之后再维护平衡即可
上述算法就是 “对顶堆” 算法
这个代码会爆空间,但很好的实现的上述过程
priority_queue<int> q1, q2;
void solve() {
while (q1.size()) q1.pop();
while (q2.size()) q2.pop();
int num, n;
cin >> num >> n;
cout << num << " " << (n + 1) / 2 << "\n";
int a;
cin >> a;
cout << a << " ";
q2.push(-a);
int cnt = 1;
for (int i = 2; i <= n; ++i) {
cin >> a;
if (a < -q2.top()) q1.push(a);
else
q2.push(-a);
int s = q1.size();
if (s > i / 2) {
q2.push(-q1.top());
q1.pop();
}
if (s < i / 2) {
q1.push(-q2.top());
q2.pop();
}
if (i & 1) {
cout << -q2.top() << " ";
if (++cnt % 10 == 0) cout << endl;
}
}
cout << "\n";
}
AC 代码
vector<short> a;
void solve() {
a.clear();
int k, n;
cin >> k >> n;
cout << k << " " << (n + 1) / 2 << "\n";
for (int i = 1; i <= n; ++i) {
short x;
cin >> x;
a.insert(upper_bound(a.begin(), a.end(), x), x);
if (i & 1) cout << a[(i - 1) / 2] << " ";
if (i % 20 == 0) cout << "\n";
}
cout << "\n";
}
0x05 基本算法-排序的更多相关文章
- JS的十大经典算法排序
引子 有句话怎么说来着: 雷锋推倒雷峰塔,Java implements JavaScript. 当年,想凭借抱Java大腿火一把而不惜把自己名字给改了的JavaScript(原名LiveScript ...
- js 数组排序和算法排序
1.算法排序 a.插入排序 var arr = [23,34,3,4,23,44,333,444]; var arrShow = (function insertionSort(array){ if( ...
- 【编程练习】收集的一些c++代码片,算法排序,读文件,写日志,快速求积分等等
写日志: class LogFile { public: static LogFile &instance(); operator FILE *() const { return m_file ...
- js算法排序
一.选择算法排序(算法时间复杂度为O(n²)级别) 选择排序就是选择数组中的最小的树,依次排序.第一次选择最小的数放在第一位,第二次从剩余的元素中寻找最小的元素放在第二位,第三次在剩余的数中选择最小的 ...
- 之前写的收集的一些c++代码片,算法排序,读文件,写日志,快速求积分等等
写日志: class LogFile { public: static LogFile &instance(); operator FILE *() const { return m_file ...
- LeetCode初级算法--排序和搜索01:第一个错误的版本
LeetCode初级算法--排序和搜索01:第一个错误的版本 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.cs ...
- Rxjs入门实践-各种排序算法排序过程的可视化展示
Rxjs入门实践-各种排序算法排序过程的可视化展示 这几天学习下<算法>的排序章节,具体见对排序的总结,想着做点东西,能将各种排序算法的排序过程使用Rxjs通过可视化的方式展示出来,正好练 ...
- 常用算法——排序(一)
排序(Sort)是计算机程序设计中的一种重要操作,也是日常生活中经常遇到的问题.例如,字典中的单词是以字母的顺序排列,否则,使用起来非常困难.同样,存储在计算机中的数据的次序,对于处理这些数据的算法的 ...
- 常用算法——排序(二)
简单选择排序法 选择排序(Selection Sort)的基本思想:对n个记录进行扫描,选择最小的记录,将其输出,接着在剩下的n-1个记录中扫描,选择最小的记录将其输出,--不断重复这个过程,直到只剩 ...
- Python之路【第二十四篇】Python算法排序一
什么是算法 1.什么是算法 算法(algorithm):就是定义良好的计算过程,他取一个或一组的值为输入,并产生出一个或一组值作为输出.简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果. ...
随机推荐
- [FJOI2017]矩阵填数 (容斥原理)
题目传送门 现在看来熊猫杯的J题原来是个容斥套路题,按照值域排序后根据值域划分方块数,枚举子集容斥计算即可. #include<cstdio> #include<algorithm& ...
- C语言所有运算符及优先级、结合性
C 语言所有运算符及优先级.结合性 参考:<C Primer Plus 第六版> Tip:有关优先级.结合性的表格在最后面. [1]算数运算符 '+'("加号")(二元 ...
- [ABC265G] 012 Inversion
Problem Statement You are given a sequence $A=(A_1,\ldots,A_N)$ of length $N$. Each element is $0$, ...
- Elasticsearch入门到进阶
Elasticsearch 一.Elasticsearch 是什么(中文官网)? Elasticsearch 是一个分布式的免费开源搜索和分析引擎,适用于包括文本.数字.地理空间.结构化和非结构化数据 ...
- TCP/IP协议---三次握手和四次挥手
TCP首部的数据格式 其中, 源端口号和目的端口号各占16位,端口范围1~65535.1024以下为知名端口,1024~65535是供用户使用.源端口,目的端口,源ip,目的ip这四个值唯一确定一个T ...
- 【内核】kernel 热升级-1:kexec 机制
内核热升级是指,预先准备好需要升级的内核镜像文件,在秒级时间内,完成内核切换,追求用户服务进程无感知. 欧拉操作系统提供了一套比较成熟的解决方案,该解决方案提供了用户态程序和内核态程序两部分: kex ...
- Kernel Memory 入门系列:Semantic Kernel 插件
Kernel Memory 入门系列:Semantic Kernel 插件 Kernel Memory 本身提供了完整的RAG能力,这部分能力如果通过Semantic Kernel Memory的话, ...
- JPA复杂查询时间查询分页排序
JPA复杂查询时间查询分页排序 JPA复杂查询时间查询分页排序,工作上用到,因为项目是jpa,记录.代码囊括了:查询条件+时间范围+分页+排序 其实我也不太想用jpa,但是他也有优点,操作可以兼容多种 ...
- Linux 多路复用(多路转接)
出现原因 如果需要从一个文件描述符中读取数据,然后将数据写入到另一个文件描述符时,可以按照如下的阻塞 IO : while ((n = read(STDIN_FILENO, buf, BUFFER_S ...
- rust angular 自签名证书 wss
项目中采用 wss 来建立的前后端连接, 但是并没有用到认证的证书, 所以自己用 openssl 生成了私钥, 自签名证书来使用: 这里就不再赘述 Wss 连接过程, 直接上手操作: 1. 生成私钥, ...