vp 2024冬季PAT甲级
前言
最后10分钟极限AK,第三题太BT了,用vector或者deque模拟都会TLE,只能上平衡树才能过。
此次做崩了,中途就把录屏停了,因此没有录屏
题目总览



题目细览
第1题 A-1 Super A - B

思路
以字符串形式读入a和b,通过比较a是否小于b来判断答案是否为负数,然后先pop掉a和b最后的'0',然后通过给短的那个字符串末尾补'0'来对其两个字符串,然后根据答案是否为负数选择是否交换a和b以确保a > b,下标从2开始模拟,如果a[i] - b[i]够减就直接减,否则一直查询上一个数是否够减,然后将上一个数减一,输出前注意也要pop掉答案最后的'0',最后输出的时候先输出符号在输出数值。
我的AC代码
#include <bits/stdc++.h>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
std::string sa, sb;
std::cin >> sa >> sb;
while (sa.back() == '0') {
sa.pop_back();
}
while (sb.back() == '0') {
sb.pop_back();
}
bool isNeg = (sa < sb);
int lena = sa.size();
int lenb = sb.size();
if (lena < lenb) {
for (int i = 0; i < lenb - lena; i++) {
sa += '0';
}
} else if (lena > lenb) {
for (int i = 0; i < lena - lenb; i++) {
sb += '0';
}
}
if (isNeg) {
std::swap(sa, sb);
}
std::string ans = "0.";
for (int i = 2; i < sa.size(); i++) {
int d = sa[i] - sb[i];
if (d < 0) {
d += 10;
for (int j = i - 1; j >= 2; j--) {
if (ans[j] == '0') {
ans[j] = '9';
} else {
ans[j]--;
break;
}
}
ans += char('0' + d);
} else {
ans += char('0' + d);
}
}
while (ans.back() == '0') {
ans.pop_back();
}
std::cout << (isNeg ? "-" : "") << ans << "\n";
return 0;
}
第2题 A-2 Gala Night

思路
必须要要优化操作2的时间复杂度,如果使用了过多的map和set会TLE,参考我提交的九发TLE。思路就看代码吧,太细了说不上来。
我的AC代码
#include <bits/stdc++.h>
void solve() {
int n;
std::cin >> n;
std::unordered_map<std::string, std::vector<int>> map;
std::unordered_map<int, std::string> at;
std::vector<int> all;
all.reserve(n);
std::unordered_map<int, bool> won;
for (int i = 0; i < n; i++) {
std::string id;
int x;
std::cin >> id >> x;
map[id].push_back(x);
at[x] = id;
all.push_back(x);
}
std::sort(all.begin(), all.end());
int q;
std::cin >> q;
for (int qi = 0; qi < q; qi++) {
int op;
std::cin >> op;
if (op == 1) {
int x;
std::cin >> x;
auto it = std::lower_bound(all.begin(), all.end(), x);
if (it == all.end()) {
std::cout << "ERROR\n";
} else {
std::cout << at[*it] << "\n";
won[*it] = true;
}
} else if (op == 2) {
std::string id;
std::cin >> id;
auto it = map.find(id);
if (it == map.end()) {
std::cout << "ERROR\n";
} else {
const auto& t = it->second;
std::vector<int> ans;
for (const auto& _ : t) {
if (won[_]) {
ans.push_back(_);
}
}
if (ans.empty()) {
std::cout << "\n";
} else {
for (int i = 0; i < ans.size(); i++) {
std::cout << ans[i] << " \n"[i + 1 == ans.size()];
}
}
}
} else {
int x;
std::cin >> x;
auto it = std::lower_bound(all.begin(), all.end(), x);
if (it == all.end()) {
std::cout << "ERROR\n";
} else if (*it != x) {
std::cout << "ERROR\n";
} else {
std::cout << at[*it] << "\n";
won[*it] = true;
}
}
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int T = 1;
// std::cin >> T;
for (int Ti = 0; Ti < T; Ti++) {
solve();
}
return 0;
}
第3题 A-3 Dancing Stacks

思路
实现一个数据结构,类似于栈,除了支持push和pop以外,还需要额外支持两个操作,一个是反转该数据结构内所有元素,另一个是两两交换数据结构内所有元素(从栈顶开始),如果操作到最后只剩下一个则跳过。我一开始打算用vector或者deque模拟,但是都TLE了,于是考虑用平衡树,我用了两个Treap来维护。
我的AC代码
#include <bits/stdc++.h>
using i64 = long long;
constexpr int inf1 = 1E9;
constexpr i64 inf2 = 1E18;
constexpr int P1 = 1E9 + 7, P2 = 998'244'353;
struct Node {
int val, pri, sz, rev, l, r;
};
std::vector<Node> tr(200001);
int cnt = 0;
int new_node(int v) {
++cnt;
tr[cnt].val = v;
tr[cnt].pri = rand();
tr[cnt].sz = 1;
tr[cnt].rev = 0;
tr[cnt].l = tr[cnt].r = 0;
return cnt;
}
void push(int t) {
if (t && tr[t].rev) {
tr[t].rev = 0;
std::swap(tr[t].l, tr[t].r);
if (tr[t].l) {
tr[tr[t].l].rev ^= 1;
}
if (tr[t].r) {
tr[tr[t].r].rev ^= 1;
}
}
}
void update(int t) {
if (t) {
tr[t].sz = tr[tr[t].l].sz + tr[tr[t].r].sz + 1;
}
}
void split(int t, int k, int& a, int& b) {
if (!t) {
a = b = 0;
return;
}
push(t);
int leftSize = tr[tr[t].l].sz;
if (k <= leftSize) {
split(tr[t].l, k, a, tr[t].l);
b = t;
} else {
split(tr[t].r, k - leftSize - 1, tr[t].r, b);
a = t;
}
update(t);
}
int merge(int a, int b) {
if (!a) return b;
if (!b) return a;
push(a);
push(b);
if (tr[a].pri > tr[b].pri) {
tr[a].r = merge(tr[a].r, b);
update(a);
return a;
} else {
tr[b].l = merge(a, tr[b].l);
update(b);
return b;
}
}
int pop_front(int& root) {
push(root);
int left, right;
split(root, 1, left, right);
int val = tr[left].val;
root = right;
return val;
}
int pop_back(int& root) {
push(root);
int sz = tr[root].sz;
int left, right;
split(root, sz - 1, left, right);
root = left;
return right;
}
void solve() {
int q;
std::cin >> q;
int E = 0, O = 0;
int n = 0;
for (int qi = 0; qi < q; qi++) {
int op;
std::cin >> op;
if (op == 0) {
int x;
std::cin >> x;
int newnode = new_node(x);
int newE = merge(newnode, O);
O = E;
E = newE;
n++;
} else if (op == 1) {
if (n == 0) {
std::cout << "-1\n";
} else {
int val = pop_front(E);
std::cout << val << "\n";
int oldO = O;
O = E;
E = oldO;
n--;
}
} else if (op == 2) {
if (n == 0) continue;
if (E) tr[E].rev ^= 1;
if (O) tr[O].rev ^= 1;
if (n % 2 == 0) {
std::swap(E, O);
}
} else {
if (n == 0) continue;
if (n % 2 == 0) {
std::swap(E, O);
} else {
int last = pop_back(E);
int newE = merge(O, last);
O = E;
E = newE;
}
}
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int T = 1;
// std::cin >> T;
for (int Ti = 0; Ti < T; Ti++) {
solve();
}
return 0;
}
第4题 A-4 Stop Blowing, Wind of Longing

思路
dijkstra两遍,第一遍尝试不经过"想你的风还是吹到了xx"的地点,此时dijkstra的时候要注意如果有多条最短路时,要走经过地点最多的路。如果第一次dijkstra的结果是无法到达,那么进行第二次dijkstra,这次的dijkstra允许经过"想你的风还是吹到了xx"的地点,同样的,如果如果有多条最短路时,要走经过"想你的风还是吹到了xx"地点最少的路。最后按要求输出答案即可。
我的AC代码
#include <bits/stdc++.h>
constexpr int inf = 2E9;
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<std::vector<std::array<int, 2>>> adj(n + 1);
for (int i = 0; i < m; i++) {
int u, v, w;
std::cin >> u >> v >> w;
adj[u].push_back({v, w});
adj[v].push_back({u, w});
}
int t;
std::cin >> t;
std::vector<bool> is(n + 1);
for (int i = 0; i < t; i++) {
int x;
std::cin >> x;
is[x] = true;
}
int st, ed;
std::cin >> st >> ed;
auto dijkstra1 = [&]() {
std::vector<int> dist(n + 1, inf);
std::vector<int> cnt(n + 1);
std::vector<bool> vis(n + 1);
using Node = std::array<int, 2>;
std::priority_queue<Node, std::vector<Node>, std::greater<>> heap;
heap.push({0, st});
dist[st] = 0;
if (is[st]) {
return std::array{inf, -1};
}
cnt[st] = 1;
while (heap.size()) {
auto [distance, u] = heap.top();
heap.pop();
if (vis[u]) {
continue;
}
vis[u] = true;
for (const auto& [v, w] : adj[u]) {
if (is[v]) {
continue;
}
if (distance + w < dist[v]) {
dist[v] = distance + w;
cnt[v] = cnt[u] + 1;
heap.push({dist[v], v});
} else if (distance + w == dist[v]) {
cnt[v] = std::max(cnt[v], cnt[u] + 1);
}
}
}
return std::array{dist[ed], cnt[ed]};
};
auto [dist1, cnt1] = dijkstra1();
if (dist1 != inf) {
std::cout << dist1 << " " << cnt1 << "\n";
return;
}
auto dijkstra2 = [&]() {
std::vector<int> dist(n + 1, inf);
std::vector<int> cnt(n + 1);
std::vector<bool> vis(n + 1);
using Node = std::array<int, 2>;
std::priority_queue<Node, std::vector<Node>, std::greater<>> heap;
heap.push({0, st});
dist[st] = 0;
cnt[st] = (is[st] ? 1 : 0);
while (heap.size()) {
auto [distance, u] = heap.top();
heap.pop();
if (vis[u]) {
continue;
}
vis[u] = true;
for (const auto& [v, w] : adj[u]) {
if (distance + w < dist[v]) {
dist[v] = distance + w;
if (is[v]) cnt[v] = cnt[u] + 1;
else cnt[v] = cnt[u];
heap.push({dist[v], v});
} else if (distance + w == dist[v]) {
if (is[v]) cnt[v] = std::min(cnt[v], cnt[u] + 1);
else cnt[v] = std::min(cnt[v], cnt[u]);
}
}
}
return std::array{dist[ed], cnt[ed]};
};
auto [dist2, cnt2] = dijkstra2();
std::cout << dist2 << " " << cnt2 << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int T = 1;
// std::cin >> T;
for (int Ti = 0; Ti < T; Ti++) {
solve();
}
return 0;
}

浙公网安备 33010602011771号