2024年2月1号题解
P1160 队列安排
解题思路
- 首先因为要不停插入和删除一个数,所以自就要想到链表用链表来组织数据,因为链表适合频繁的插入和删除操作。
- 因为不是在一个固定的位置中操作所以链表删除和插入都需要O(n)的时间复杂度,但如果我们可以直接知道要插入和删除的位置,就可以实现O(1)了。
- 那么我们只需要一个哈希表来存储编号对应的节点的地址就可以找到节点了,那么我们就可以快速找到插入和删除的位置了。
- 但删除也可以用另一个哈希表来标记是不是要删除,来决定要不要输出。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define u unsigned
#define ll long long
#define sc scanf
#define pr printf
#define fr(i, j, n) for (int i = j; i < n; i++)
#define N 100001
int n;
int m;
int b[2];
bool mark[N];
ll map[N];
struct Link {
int val;
struct Link* left;
struct Link* right;
};
typedef struct Link node;
typedef struct Link* link;
link makeNode(int n) {
link ans = (link)malloc(sizeof(node));
ans->val = n;
ans -> right = ans->left = NULL;
return ans;
}
int main(int argc, char* argv[])
{
link head = makeNode(1);
link tail = head;
link t = NULL;
link p = NULL;
map[1] = head;
sc("%d", &n);
for (int i = 1; i < n; i++) {
sc("%d%d", b, b + 1);
if (b[1]) {
t = makeNode(i + 1);
p = map[b[0]];
if (p->right) {
t->right = p->right;
p->right = t;
t->right->left = t;
t->left = p;
}
else {
p->right = t;
t->left = p;
}
if (tail->val == b[0]) {
tail = t;
}
map[i + 1] = t;
}
else {
t = makeNode(i + 1);
p = map[b[0]];
if (p->left) {
t->right = p;
p->left->right = t;
t->left = p->left;
p->left = t;
}
else {
t->right = p;
p->left = t;
}
if (head->val == b[0]) {
head = t;
}
map[i + 1] = t;
}
}
sc("%d", &m);
for (int i = 0; i < m; i++) {
sc("%d", &n);
mark[n] = 1;
}
p = head;
while (p) {
if (!mark[p->val]) {
pr("%d ", p->val);
}
p = p->right;
}
return 0;
}
P2234 [HNOI2002] 营业额统计
解题思路
- 根据贪心的思想可以知道只要在前一天找到在数轴上最接近当前营业额就可以使得每天营业额最小
- 那么如果前面的营业额有序的话就可以用二分来找到离当前营业额中最接近的数
- 所以我们就可以每次插入一个数,来保证数组有序
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define u unsigned
#define ll long long
#define sc scanf
#define pr printf
#define fr(i, j, n) for (int i = j; i < n; i++)
#define N 40000
ll a[N];
ll b[N];
int n;
ll ans;
int size;
int main(int argc, char* argv[])
{
sc("%d", &n);
for (int i = 0; i < n; i ++) {
sc("%lld", a + i);
}
ans += a[0];
b[size ++] = a[0];
for (int i = 1; i < n; i ++) {
int l = 0;
int r = size - 1;
int ans1 = -1;
int ans2 = -1;
while(l <= r) {
int mid = (l + r) / 2;
if (b[mid] >= a[i]) {
ans1 = mid;
r = mid - 1;
}
else {
l = mid + 1;
}
}
l = 0;
r = size - 1;
while(l <= r) {
int mid = (l + r) / 2;
if (b[mid] <= a[i]) {
ans2 = mid;
l = mid + 1;
}
else {
r = mid - 1;
}
}
if (ans1 == -1) {
int aa = b[ans2] - a[i];
aa = aa < 0? ~aa + 1: aa;
ans += aa;
}
else if (ans2 == -1) {
int aa = b[ans1] - a[i];
aa = aa < 0? ~aa + 1: aa;
ans += aa;
}
else {
int aa = b[ans1] - a[i];
int bb = b[ans2] - a[i];
aa = aa < 0? ~aa + 1: aa;
bb = bb < 0? ~bb + 1: bb;
if (aa <= bb) {
ans += aa;
}
else {
ans += bb;
}
}
l = 0;
r = size - 1;
int k = -1;
while(l <= r) {
int mid = (l + r) / 2;
if (b[mid] <= a[i]) {
k = mid;
l = mid + 1;
}
else {
r = mid - 1;
}
}
for (int i = size - 1; i > k; i --) {
b[i + 1] = b[i];
}
b[k + 1] = a[i];
size++;
}
pr("%d", ans);
return 0;
}