[算法进阶0x10]基本数据结构C作业总结
t1-Supermarket 超市利润
题目大意
给定n个商品,每个商品有利润pi和过期时间di。每天只能卖一个商品,过期商品不能卖。求如何安排每天卖的商品可以使收益最大。
分析
一开始打了一个复杂度跑不满\(n^2\)的暴力发现T掉了,就换成了\(nlogn\)的算法,但是依旧是T掉了,而且T飞掉了,看到洛谷里有人发帖子说只能用cin才A掉了。
首先,很明显最优的是一直在卖东西,那么可以将所有的已经当前决定是卖掉的物品放入一个小根堆中。
我们先将这些物品按照日期从小到大排序
分成3种情况讨论:
- 如果当前的过期日期=堆中元素个数,说明在过期最后一天不能卖这个物品了,那么就把堆顶取出,弹入较大的。
- 如果当前的过期日期<堆中元素个数,说明可以直接卖掉,那么直接弹入堆中。
- 如果当前的过期日期>堆中元素个数,不存在这种情况,直接跳过
每一次操作后都要维护堆。
ps.前辈的经验,不要用while (scanf("%d", &n)!=EOF)
,T到自己怀疑人生,而且自己学校的oj还有手写堆,更加怀疑人生。
ac代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 10005
#pragma GCC optimize(2)
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; T fl = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') fl = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= fl;
}
struct node {
int p, d;
inline bool operator <(const node &rhs) const {
return d < rhs.d;
}
}a[N];
int n, ans;
bool vis[N];
struct Heap {
int heap[N], tot;
inline void up(int u) {
while (u > 1) {
if (heap[u] < heap[u >> 1]) {
swap(heap[u], heap[u >> 1]);
u >>= 1;
}
else break;
}
}
inline void insert(int v) {
heap[++ tot] = v;
up(tot);
}
inline void down(int u) {
int s = u << 1;
while (s <= tot) {
if (s < tot && heap[s] > heap[s + 1]) s ++;
if (heap[s] < heap[u]) {
swap(heap[s], heap[u]);
u = s;
s = u << 1;
}
else break;
}
}
inline void pop() {
heap[1] = heap[tot --];
down(1);
}
inline int get_top() {
return heap[1];
}
inline void clear() {
memset(heap, 0, sizeof(heap));
tot = 0;
}
}heap;
int main() {
while (cin>> n) {
heap.clear();
ans = 0;
for (register int i = 1; i <= n; i ++) {
read(a[i].p); read(a[i].d);
}
sort(a + 1, a + 1 + n);
for (register int i = 1; i <= n; i ++) {
if (a[i].d == heap.tot) {
if (a[i].p > heap.get_top()) {
heap.pop();
heap.insert(a[i].p);
}
}
else if (a[i].d > heap.tot) {
heap.insert(a[i].p);
}
}
for (register int i = 1; i <= heap.tot; i ++)
ans += heap.heap[i];
printf("%d\n", ans);
}
return 0;
}
t2-Sequence
题目大意
给你m个长度为n的数列,让你从m个队列中每一个数列中取出一个数,求出字典序的第n小。
分析
这是k小堆的模板,其实就是维护一个长度固定的堆,不做赘述。
ac代码
#include <bits/stdc++.h>
#define pii pair<int, int>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; T fl = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') fl = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= fl;
}
int n, m;
int a[2005], b[2005];
void merge(int *a, int *b, int *c, int n) {
priority_queue<pii, vector<pii>, greater<pii> >q;
for (int i = 0; i < n; i ++) q.push(pii(a[i] + b[0], 0));
for (int i = 0; i < n; i ++) {
int x = q.top().first, y = q.top().second;
q.pop();
c[i] = x;
if (y + 1 < n) q.push(pii(x - b[y] + b[y + 1], y + 1));
}
}
int main() {
int cas; read(cas);
while (cas --) {
read(m); read(n);
for (int i = 0; i < n; i ++) read(b[i]);
sort(b, b + n);
for (int i = 1; i < m; i ++) {
for (int j = 0; j < n; j ++) read(a[j]);
sort(a, a + n);
merge(b, a, b, n);
}
for (int i = 0; i < n; i ++) printf("%d ", b[i]);
puts("");
}
return 0;
}
t3-数据备份 Backup
不做赘述
题解链接:https://www.cnblogs.com/chhokmah/p/10557925.html
t4-黑匣子(blackbox)
分析
开两个堆,一个大根堆维护1~i-1小元素,一个小根堆维护i~n小元素
添加元素时,如果元素小于大根堆堆顶,那么把大根堆堆顶出堆,将此元素加入大根堆
否则将元素加入小根堆
查询值即为小根堆顶,查询完后将小根堆顶加入大根堆
ac代码
#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define N 200005
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; T fl = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') fl = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= fl;
}
priority_queue<int> qmax;
priority_queue<int, vector<int>, greater<int> >qmin;
int a[N];
int n, m;
int main() {
read(m); read(n);
for (int i = 1; i <= m; i ++) read(a[i]);
int j = 1;
for (int i = 1; i <= n; i ++) {
int x; read(x);
for (; j <= x; j ++) {
if (!qmax.empty() && a[j] <= qmax.top()) {
qmin.push(qmax.top());
qmax.pop();
qmax.push(a[j]);
}
else qmin.push(a[j]);
}
printf("%d\n", qmin.top());
qmax.push(qmin.top());
qmin.pop();
}
return 0;
}
t5-生日礼物
题目大意
n个数分成m段,使其每一段和和最大值
分析
不做赘述:https://www.cnblogs.com/chhokmah/p/10558237.html
t6-合并果子
太简单了,优先队列取最小的两个,再把和压回去,写堆也可以。
ac代码
#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; T fl = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') fl = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= fl;
}
priority_queue<int, vector<int>, greater<int> >q;
int n;
ll ans = 0;
int main() {
read(n);
for (int i = 1; i <= n; i ++) {
int x;
read(x);
q.push(x);
}
for (int i = 1; i < n; i ++) {
int x1 = q.top();
q.pop();
int x2 = q.top();
q.pop();
ans += x1 + x2;
q.push(x1 + x2);
}
printf("%lld", ans);
return 0;
}
t7-荷马史诗
分析
首先明确需要维护什么。转换一下题意,不难知道我们需要维护的是最短的带权路径之和和该哈夫曼树的高度。然后便是如何维护,由于不需要知道哈夫曼树的具体形态,我们便可以按照哈夫曼树的构造方式,将当前最小的K个节点合并为1个父节点,直至只有一个父节点。看到“将最小K个节点合并”便可以明确使用优先队列(二叉堆)进行维护。
最后,我们需要注意一个细节。因为每次都是将k个节点合并为1个(减少k-1个),一共要将n个节点合并为1个,如果(n-1)%(k-1)!=0 则最后一次合并时不足k个。也就表明了最靠近根节点的位置反而没有被排满,因此我们需要加入k-1-(n-1)%(k-1)个空节点使每次合并都够k个节点(也就是利用空节点将其余的节点挤到更优的位置上)。
ac代码
#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; T fl = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') fl = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= fl;
}
struct node {
ll w, h;
node() {
w = 0, h = 0;
}
node(ll w, ll h): w(w), h(h){}
bool operator <(const node &rhs) const {
if (w != rhs.w) return w > rhs.w;
return h > rhs.h;
}
};
__gnu_pbds::priority_queue <node, std::less<node>, __gnu_pbds::pairing_heap_tag> q;
int n, k, cnt;
ll tmp, mx, ans;
int main() {
read(n); read(k);
for (int i = 1; i <= n; i ++) {
read(tmp);
q.push(node(tmp, 1));
}
if ((n - 1) % (k - 1) != 0) cnt = k - 1 -(n - 1) % (k - 1);
for (int i = 1; i <= cnt; i ++) {
q.push(node(0, 1));
}
cnt += n;
while (cnt > 1) {
tmp = mx = 0;
for (int i = 1; i <= k; i ++) {
tmp += q.top().w;
mx = max(mx, q.top().h);
q.pop();
}
ans += tmp;
q.push(node(tmp, mx + 1));
cnt -= k - 1;
}
printf("%lld\n%lld\n", ans, q.top().h - 1);
return 0;
}
t8-双栈排序
分析
首先必然要先考虑是否有解。对于没有解的情况,必然是当到了某一个数x0时,栈1,栈2队首元素都不能弹出,并且x0要比栈1、2的队首元素都要大,这时就不能排序了。
所以考虑什么时候A、B不能在同一个栈中的情况:
当且仅当,A<B,并且存在C,使得A>C.并满足A位置在B前面,B位置在C前面。就是说,由于C的存在,A不能pop掉,但是B放进去,A就永远pop不了了。
这样就可以找到所有不能和x0在同一个栈里的所有位置上的数了。
判断无解时,将所有上述的A和B之间连一条无向边,用二分图染色或者带偏移量的并查集都可以。
输出时,因为要字典序最小,所以第一个元素必然要放进栈1,这样可以预处理出来所有数要进入哪一个栈。能进栈1的都进栈1.
然后模拟实现,每次先要判断是否可以pop掉栈顶元素,然后按照之前的预处理的方案放进数就可以了。
ac代码
#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define N 10005
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; T fl = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') fl = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= fl;
}
struct edge {
int to, nt;
}E[N];
int H[N], fmn[N], a[N], p[3][N], c[N], l[N];
int n, cnt;
void add_edge(int u, int v) {
E[++ cnt] = (edge){v, H[u]};
H[u] = cnt;
}
void dfs(int u, int col) {
if (!c[u]) c[u] = col;
else if (c[u] != col) {
printf("0\n");
exit(0);
}
else return;
for (int e = H[u]; e; e = E[e].nt) {
int v = E[e].to;
dfs(v, 3 - col);
}
}
int main() {
read(n);
for (int i = 1; i <= n; i ++) {
read(a[i]);
}
fmn[n] = a[n];
for (int i = n - 1; i >= 1; i --) fmn[i] = min(fmn[i + 1], a[i]);
p[1][0] = 1002, c[n + 1] = 1; p[2][0] = 1002; a[n + 1] = 1001;
for (int i = 1; i < n - 1; i ++) {
for (int j = i + 1; j < n; j ++) {
if (a[i] < a[j] && fmn[j + 1] < a[i]) {
add_edge(i, j);
add_edge(j, i);
}
}
}
for (int i = 1; i <= n; i ++) {
if (!c[i]) dfs(i, 1);
}
int x = 1;
for (int i = 1; i <= n + 1; i ++) {
while (233) {
if (p[1][l[1]] == x) {
x ++;
l[1] --;
printf("b ");
}
else if (p[2][l[2]] == x) {
x ++;
l[2] --;
printf("d ");
}
else break;
}
p[c[i]][++ l[c[i]]] = a[i];
if (i < n + 1) printf("%c ", char(2 * c[i] + 95));
}
return 0;
}
t9-Subway tree systems
分析
树的最小表示法:从下向上把子树排序,这样向上,最后表示出来的就是最小表示的了,那么就有序了,就可以直接比较字符串就能判断两棵树是否相同。
ac代码
#include <vector>
#include <cstdio>
#include <string>
#include <algorithm>
#define ms(a, b) memset(a, b, sizeof(a))
#define LL long long
using namespace std;
char s[3005];
string dfs(int x) {
vector<string> ch;
while (s[x] == '0') {
string t = "(" + dfs(x + 1);
ch.push_back(t);
x += t.length();
}
sort(ch.begin(), ch.end());
string res = "";
vector<string>::iterator it;
for (it = ch.begin(); it != ch.end(); it ++) res += *it;
return res + ")";
}
int main() {
int cas;
scanf("%d", &cas);
for (int _t = 1; _t <= cas; _t ++) {
scanf("%s", s);
string t = dfs(0);
scanf("%s", s);
if (dfs(0) == t) puts("same");
else puts("different");
}
return 0;
}
t10-Sliding Window 滑窗
分析
单调队列模板
ac代码
# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
# pragma GCC optimize(2)
using namespace std;
inline int gi(){
int w=0,x=0;char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return w?-x:x;
}
# define N 1000005
deque<int>qmax,qmin;
int ansmin[N],ansmax[N],a[N];
int n,k;
void write(int x){
if (x>9) write(x/10);
putchar(x%10+'0');
}
int main(){
n=gi(),k=gi();
for (int i=1;i<=n;i++) a[i]=gi();
for (int i=1;i<=n;i++){
while (!qmax.empty()&&i-qmax.front()+1>k) qmax.pop_front();
while (!qmin.empty()&&i-qmin.front()+1>k) qmin.pop_front();
while (!qmax.empty()&&a[i]>a[qmax.back()]) qmax.pop_back();
while (!qmin.empty()&&a[i]<a[qmin.back()]) qmin.pop_back();
qmax.push_back(i); qmin.push_back(i);
ansmax[i]=a[qmax.front()]; ansmin[i]=a[qmin.front()];
}
for (int i=k;i<=n;i++) printf("%d ",ansmin[i]); puts("");
for (int i=k;i<=n;i++) printf("%d ",ansmax[i]);
return 0;
}
[算法进阶0x10]基本数据结构C作业总结的更多相关文章
- [算法进阶0x10]基本数据结构A作业总结
在线题目\(oj\)评测地址:https://xoj.red/contests/show/1237 T1-Editor(hdu4699) 题目描述 维护一个整数序列的编辑器,有以下5种操作,操作总数不 ...
- 模板——最小生成树kruskal算法+并查集数据结构
并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每 ...
- 《算法竞赛进阶指南》0x10 基本数据结构 Hash
Hash的基本知识 字符串hash算法将字符串看成p进制数字,再将结果mod q例如:abcabcdefg 将字母转换位数字(1231234567)=(1*p9+2*p8+3*p7+1*p6+2*p5 ...
- 「【算法进阶0x30】数学知识A」作业简洁总结
t1-Prime Distance 素数距离 大范围筛素数. t2-阶乘分解 欧拉筛素数后,按照蓝皮上的式子筛出素数. 复杂度:O(nlogn) t3-反素数ant 搜索 t4-余数之和 整除分块+容 ...
- 算法进阶之Leetcode刷题记录
目录 引言 题目 1.两数之和 题目 解题笔记 7.反转整数 题目 解题笔记 9.回文数 题目 解题笔记 13.罗马数字转整数 题目 解题笔记 14.最长公共前缀 题目 解题笔记 20.有效的括号 题 ...
- 算法初步---基本的数据结构(java为例)
最近搞算法,觉得超级吃力的,一直以为数学好的,数学可以考试满分,算法一定没什么问题,贱贱地,我发现我自己想多了,还是自己的基础薄弱吧,今天我来补补最基础的知识. 算法(Algorithm)是指解题方案 ...
- CNN:人工智能之神经网络算法进阶优化,六种不同优化算法实现手写数字识别逐步提高,应用案例自动驾驶之捕捉并识别周围车牌号—Jason niu
import mnist_loader from network3 import Network from network3 import ConvPoolLayer, FullyConnectedL ...
- NN:神经网络算法进阶优化法,进一步提高手写数字识别的准确率—Jason niu
上一篇文章,比较了三种算法实现对手写数字识别,其中,SVM和神经网络算法表现非常好准确率都在90%以上,本文章进一步探讨对神经网络算法优化,进一步提高准确率,通过测试发现,准确率提高了很多. 首先,改 ...
- Quartz.Net进阶之一:初识Job作业和触发器
前几天写了一篇有关Quartz.Net入门的文章,大家感觉不过瘾,想让我在写一些比较深入的文章.其实这个东西,我也是刚入门,我也想继续深入了解一下,所以就努力看了一些资料,然后自己再整理和翻译 ...
随机推荐
- PAT 7-12 拯救007
在老电影“007之生死关头”(Live and Let Die)中有一个情节,007被毒贩抓到一个鳄鱼池中心的小岛上,他用了一种极为大胆的方法逃脱 —— 直接踩着池子里一系列鳄鱼的大脑袋跳上岸去!(据 ...
- 分布式Tomcat session会话Sticky Sessions问题
分布式session会话Sticky Sessions - tomcat_baby的专栏 - CSDN博客https://blog.csdn.net/tomcat_baby/article/detai ...
- 生命周期函数以及vue的全局注册
beforeCreate 在创造实例之前 created 创造实例以后 beforeMount 在挂载前 render 渲染节点到页面上 //将虚拟dom数组渲染出来 mounted 挂载以后 bef ...
- [转帖]Linux命令中特殊符号
Linux命令中特殊符号 转自:http://blog.chinaunix.net/uid-16946891-id-5088144.html 在shell中常用的特殊符号罗列如下:# ; ;; . ...
- day 7-6 GIL,死锁,递归锁与信号量,Event,queue,
摘要: 1.死锁与递归锁 2.信号量 3.Event 4.Timer 5.GIL 6.Queue 7.什么时候该用多线程和多进程 一. 死锁与递归锁 所谓死锁: 是指两个或两个以上的进程或线程在执行过 ...
- vue中的适配:px2rem
这应该是vue项目在适配移动端时候,最简单的方法之一下面是基本步骤(使用cnpm)1.下载并引入lib-flexible cnpm install --save lib-flexible 在main. ...
- cordova微信支付回调App闪退
这是cordova版本太高,不兼容这个插件所导致的.解决方案是修改$your_project/plugins/cordova-plugin-wechat/scripts/android-install ...
- 用junit对java代码进行测试,需要注意
1.用@Test注解的方法必须没有返回值,返回值类型无:void 2.用@Test注解的方法必须没有参数.
- Spring框架IOC和AOP的实现原理
IoC(Inversion of Control) (1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控.控制权由应用代码中 ...
- Jira的搭建
一.环境准备 jira7.2的运行是依赖java环境的,也就是说需要安装jdk并且要是1.8以上版本,如下: java -version 除此之外,我们还需要为jira创建对应的数据库.用户名和密码, ...