寫篇題解來紀念我炸掉的CSP
唯一會做的題程式碼寫掛了(痛苦面具
思路
我看到這道題第一眼想到的是線段樹,感覺可以用線段樹維護飛機入站到出戰的這段時間,想了半天想不到程式碼怎麼寫。
國內機場與國外機場要分開計算
突然發現可以用一個優先佇列來維護飛機出站的時間,給每架飛機按入站時間排好序後可以從小到大依次讓飛機入站,並比較此時是否有飛機出站,有就把隊首元素彈出。
40 pts
可以暴力列舉每一種國內機場和國際機場廊橋的分配方案。
程式碼如下:
#include <bits/stdc++.h>
#include <functional>
#define N 100010
using namespace std;
struct node {
int a, b;
} fa[N], fc[N];//分別為國外機場航班和國內機場航班
int n, m1, m2, _ans;
bool cmp(node a, node b) {
return a.a < b.a;
}
void check(int ans) {//ans表示國內機場分配的廊橋數
priority_queue <int, vector<int>, greater<int> > q;
int res = 0;
for (int i = 1; i <= m1; i++) {
int s = fc[i].a;
while (!q.empty() && s > q.top()) {
q.pop();//彈出已經出站的飛機
}
if (q.size() < ans) {
q.push(fc[i].b);//如果有空餘的廊橋就加入廊橋
res++;//答案+1
}
}
while (!q.empty())
q.pop();//清空佇列元素
for (int i = 1; i <= m2; i++) {
int s = fa[i].a;
while (!q.empty() && s > q.top()) {
q.pop();
}
if (q.size() < n - ans) {//n-ans表示國外機場分配的廊橋數
q.push(fa[i].b);//同上
res++;
}
}
_ans = max(_ans, res);
return ;
}
int main() {
scanf("%d%d%d", &n, &m1, &m2);
for (int i = 1; i <= m1; i++) {
scanf("%d%d", &fc[i].a, &fc[i].b);
}
for (int i = 1; i <= m2; i++) {
scanf("%d%d", &fa[i].a, &fa[i].b);
}
sort(fc + 1, fc + 1 + m1, cmp);
sort(fa + 1, fa + 1 + m2, cmp);//按入站時間排序
for (int i = 0; i <= n; i++) {
check(i);//暴力列舉統計答案
}
printf("%d", _ans);
return 0;
}
複雜度為O(nm logm)
100pts
以上做法的複雜度太高,這時候想有沒有什麼辦法可以一遍就統計出所有分配方案的答案,然後統計答案。
統計答案的程式碼:
for (int i = 0; i <= n; i++) {
if (ans1[i] + ans2[n - i] > maxn) {
maxn = ans1[i] + ans2[n - i];
}
}
如果給每個廊橋都編上號,每次飛機入站都選擇空閒的廊橋中編號最小的哪一個。
這樣可以排除分配方案的影響。
用一個優先佇列來維護廊橋編號,一開始將所有廊橋入隊。
對於每一架飛機可以用一個pair分別儲存飛機出站的時間以及停靠的廊橋的編號。
用優先佇列來維護pair
每次飛機入站時先比較有沒有應該出站的飛機,如果有就把他們從佇列中彈出,並把對應的廊橋編號再加入優先佇列中。
然後飛機選擇編號最小的廊橋停靠。並把對應的廊橋的ans加一。
這樣就能快速的統計出每個廊橋產生的貢獻,再把所有編號比它小的廊橋產生的貢獻加起來,用字首和陣列來維護。
最後用上面的程式碼統計一遍答案就好了。
程式碼如下:
void check() {
priority_queue<int, vector<int>, greater<int> > q;//維護廊橋編號
priority_queue<P, vector<P>, greater<P> > p;//維護飛機出站時間和停靠的廊橋的編號
for (int i = 1; i <= n; i++) {
q.push(i);//一開始所有廊橋都處於空閒狀態,把所有廊橋加入佇列。
}
for (int i = 1; i <= m1; i++) {
int s = fc[i].a;//該架飛機入站時間
while (!p.empty() && s > p.top().first) {
//彈出已經飛走的飛機並把它所停課的廊橋加入佇列
q.push(p.top().second);
p.pop();
}
if (!q.empty()) {
int id = q.top();
q.pop();//取編號最小的廊橋停靠
ans1[id]++;//該編號的廊橋產生的貢獻加一
p.push(P(fc[i].b, id));
}
}
while (!q.empty())
q.pop();
while (!p.empty())
p.pop();
//清空佇列
for (int i = 1; i <= n; i++) {
q.push(i);
}
//同上
for (int i = 1; i <= m2; i++) {
int s = fa[i].a;
while (!p.empty() && s > p.top().first) {
q.push(p.top().second);
p.pop();
}
if (!q.empty()) {
int id = q.top();
q.pop();
ans2[id]++;
p.push(P(fa[i].b, id));
}
}
for (int i = 1; i <= n; i++) {
ans1[i] += ans1[i - 1];
ans2[i] += ans2[i - 1];
}
//字首和陣列維護每種分配方案產生的答案
return;
}
複雜度 O(nlogn)
Code
#include <bits/stdc++.h>
#include <cstdio>
#include <functional>
#define P pair <int,int>
using namespace std;
struct node {
int a, b;
} fc[100010], fa[100010];
bool cmp(node a, node b) {
return a.a < b.a;
}
int n, m1, m2, maxn = -1, ans1[100010], ans2[100010];
void check() {
priority_queue<int, vector<int>, greater<int> > q;//維護廊橋編號
priority_queue<P, vector<P>, greater<P> > p;//維護飛機出站時間和停靠的廊橋的編號
for (int i = 1; i <= n; i++) {
q.push(i);//一開始所有廊橋都處於空閒狀態,把所有廊橋加入佇列。
}
for (int i = 1; i <= m1; i++) {
int s = fc[i].a;//該架飛機入站時間
while (!p.empty() && s > p.top().first) {
//彈出已經飛走的飛機並把它所停課的廊橋加入佇列
q.push(p.top().second);
p.pop();
}
if (!q.empty()) {
int id = q.top();
q.pop();//取編號最小的廊橋停靠
ans1[id]++;//該編號的廊橋產生的貢獻加一
p.push(P(fc[i].b, id));
}
}
while (!q.empty())
q.pop();
while (!p.empty())
p.pop();
//清空佇列
for (int i = 1; i <= n; i++) {
q.push(i);
}
//同上
for (int i = 1; i <= m2; i++) {
int s = fa[i].a;
while (!p.empty() && s > p.top().first) {
q.push(p.top().second);
p.pop();
}
if (!q.empty()) {
int id = q.top();
q.pop();
ans2[id]++;
p.push(P(fa[i].b, id));
}
}
for (int i = 1; i <= n; i++) {
ans1[i] += ans1[i - 1];
ans2[i] += ans2[i - 1];
}
//字首和陣列維護每種分配方案產生的答案
return;
}
int main() {
scanf("%d%d%d", &n, &m1, &m2);
for (int i = 1; i <= m1; i++) {
scanf("%d%d", &fc[i].a, &fc[i].b);
}
for (int i = 1; i <= m2; i++) {
scanf("%d%d", &fa[i].a, &fa[i].b);
}
sort(fc + 1, fc + 1 + m1, cmp);
sort(fa + 1, fa + 1 + m2, cmp);
check();
//統計答案
for (int i = 0; i <= n; i++) {
if (ans1[i] + ans2[n - i] > maxn) {
maxn = ans1[i] + ans2[n - i];
}
}
printf("%d", maxn);
return 0;
}