# 官方题解传送门

## A .操作序列

sol：如果STL熟悉，那么就是一道模拟题。就是输入有点奇葩。但是看了官方题解中提到了平衡树。嗯，没错，map和set的底层都是平衡树。红黑树不会，平衡树觉得还是fhq-treap好敲。所以，提供一份map的解法和一份fhq-treap的解法。

• map
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
map<int, int> mp;
int main() {
int t; scanf("%d", &t);
while (t--) {
int n, m, op; char c;
scanf("%d%c", &n, &c);
if (c == ' ') {
scanf("%d", &m);
bool ok = true;
for (int i = n - 30; i <= n + 30; i++)
if (mp.count(i)) ok = false;
if (ok) mp[n] = m;
continue;
}
if (n == -1) {
if (mp.empty()) puts("skipped");
else {
printf("%d\n", mp.begin()->second);
mp.erase(mp.begin());
}
} else {
if (mp.count(n)) printf("%d\n", mp[n]);
else puts("0");
}
}
return 0;
}
View Code

• fhq-treap
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MAXN = 1e6 + 10;
struct Treap {
int key, val;
int rand;
int lson, rson;
} node[MAXN];
int root, tot;
int new_node(int n, int k) {
int i = ++tot;
node[i].key = n;
node[i].val = k;
node[i].rand = rand();
node[i].lson = node[i].rson = 0;
return i;
}
void split(int rt, int& a, int& b, int k) {
if (rt == 0) {
a = b = 0;
return;
}
if (node[rt].key <= k) {
a = rt;
split(node[rt].rson, node[a].rson, b, k);
} else {
b = rt;
split(node[rt].lson, a, node[b].lson, k);
}
}
void merge(int& rt, int a, int b) {
if (a == 0 || b == 0) {
rt = a + b;
return;
}
if (node[a].rand < node[b].rand) {
rt = a;
merge(node[rt].rson, node[a].rson, b);
} else {
rt = b;
merge(node[rt].lson, a, node[b].lson);
}
}
void insert(int n, int k) {
int a, b, c;
split(root, root, c, n + 30);
split(root, a, b, n - 30 - 1);
if (b == 0) b = new_node(n, k);
merge(root, a, b);
merge(root, root, c);
}
int pop(int& point) {
if (node[point].lson == 0) {
int tmp = node[point].val;
point = node[point].rson;
return tmp;
}
return pop(node[point].lson);
}
int get_val(int n) {
int a, b, c;
split(root, root, c, n);
split(root, a, b, n - 1);
int tmp;
if (b == 0) tmp = 0;
else tmp = node[b].val;
merge(root, a, b);
merge(root, root, c);
return tmp;
}
int main() {
int t; scanf("%d", &t);
while (t--) {
int n, k; char c;
scanf("%d%c", &n, &c);
if (c == ' ') {
scanf("%d", &k);
insert(n, k);
} else if (n == -1) {
if (root == 0) puts("skipped");
else printf("%d\n", pop(root));
} else {
printf("%d\n", get_val(n));
}
}
return 0;
}
View Code

fhq-treap真的是平衡树里最简单的了，这么久没敲还能凭对代码的记忆而不是代码的理解一次敲对。

## B .树上子链

sol：和求树的直径差不多，树的直径是求树上最长的链，这题转化成求权值最大的链。

• 树的直径
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 1e5 + 10;
vector<int> edge[MAXN];
int val[MAXN];
LL res = -INF;
LL dfs(int u, int f) {
LL max1 = 0, max2 = 0;
for (int v : edge[u]) {
if (v == f) continue;
LL val = dfs(v, u);
if (val > max2) max2 = val;
if (max2 > max1) swap(max1, max2);
}
res = max(res, max1 + max2 + val[u]);
return max1 + val[u] > 0 ? max1 + val[u] : 0;
}
int main() {
int n; scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &val[i]);
for (int i = 2; i <= n; i++) {
int u, v;
scanf("%d%d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
dfs(1, -1);
printf("%lld\n", res);
return 0;
}
View Code

## C .交换游戏

sol：看了题解后感觉是一个挺裸的记忆化搜索。补掉了。

• 记忆化搜索
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MAXN = 1 << 12 | 10;
int dp[MAXN];
int n = 0;
char c = getchar();
while (c != '-' && c != 'o') c = getchar();
while (c == '-' || c == 'o') {
n = n << 1 | (c == 'o');
c = getchar();
}
return n;
}
int dfs(int n) {
if (dp[n] != -1) return dp[n];
int tmp = n, cnt = 0;
while (tmp) {
cnt ++;
tmp -= tmp & -tmp;
}
dp[n] = cnt;
int a = 1, b = 2, c = 4;
for (int i = 1; i <= 10; i++) {
if ((n & a) && (n & b) && !(n & c)) {
dp[n] = min(dp[n], dfs(n ^ a ^ b ^ c));
}
if (!(n & a) && (n & b) && (n & c)) {
dp[n] = min(dp[n], dfs(n ^ a ^ b ^ c));
}
a <<= 1, b <<= 1, c <<= 1;
}
return dp[n];
}
int main() {
memset(dp, -1, sizeof(dp));
int t; scanf("%d", &t);
while (t--) {
printf("%d\n", dfs(n));
}
return 0;
}
View Code

## D .收集纸片

sol：比赛的时候想着爆搜整张地图然后代码也没实现出来，题目中的纸片最多只有10张，所以突破口在纸片，可以枚举所以的收集顺序。那么枚举的方法就有很多了。官方题解中用了dfs的方法，那么我这里就用next_premutation这个函数来解决了。这个函数在蓝桥杯中也被多次考到。

• 全排列
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
PII p[20]; int order[20];
int main() {
int t; scanf("%d", &t);
while (t--) {
scanf("%*d%*d%d%d", &p[0].first, &p[0].second);
int n; scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &p[i].first, &p[i].second);
order[i] = i;
}
order[n + 1] = 0;
int res = INF;
do {
int sum = 0;
for (int i = 1; i <= n + 1; i++) {
sum += abs(p[order[i]].first - p[order[i - 1]].first);
sum += abs(p[order[i]].second - p[order[i - 1]].second);
}
if (sum < res) res = sum;
} while (next_permutation(order + 1, order + 1 + n));
printf("The shortest path has length %d\n", res);
}
return 0;
}
View Code

原来给出的地图大小是没用的

## E .方块涂色

sol：总共$n$行，被涂了$r$行，还剩$(n - r)$行。总共$m$列，被涂了$c$列，还剩$(m - c)$列，所以答案就是$(n - r) * (m - c)$。注意到结果可能爆int就不会错了。

• 数学
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int main() {
int n, m, r, c;
while (~scanf("%d%d%d%d", &n, &m, &r, &c))
printf("%lld\n", 1LL * (n - r) * (m - c));
return 0;
}
View Code

## F .累乘数字

sol：听说有人拿到题就直接用python高精度上了。也是一种不错的选择，容易抢一血。不过更高效的方法就是输出$n$之后再输出$d$次$00$。

• python大数
while True :
try :
n, m = map(int, input().split())
print(n * 100 ** m)
except :
break
View Code

• 数学
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int main() {
int n, m;
while (~scanf("%d%d", &n, &m)) {
printf("%d", n);
for (int i = 1; i <= m; i++)
printf("00");
puts("");
}
return 0;
}
View Code

## G .仓库选址

sol：一种比较直白的方式是枚举每个位置做仓库，然后算出这个位置的花费，然后找出最小值。复杂度是$O((n * m) * (n * m))$。官方题解就是这种方法，参照官方题解。但是其实可以把行和列分开考虑使复杂度变成$O((n * m) + (n * m))$。

• 思维
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PII;
const LL INF = 0x3f3f3f3f;
const LL MAXN = 110;
LL row[MAXN], col[MAXN];
LL cal(LL* arr, LL len) {
LL res = INF;
for (LL i = 1; i <= len; i++) {
LL sum = 0;
for (LL j = 1; j <= len; j++)
sum += abs(i - j) * arr[j];
res = min(res, sum);
}
return res;
}
int main() {
LL t; scanf("%lld", &t);
while (t--) {
LL n, m, k;
scanf("%lld%lld", &m, &n);
memset(row, 0, sizeof(row));
memset(col, 0, sizeof(col));
for (LL i = 1; i <= n; i++) {
for (LL j = 1; j <= m; j++) {
scanf("%lld", &k);
row[i] += k;
col[j] += k;
}
}
printf("%lld\n", cal(row, n) + cal(col, m));
}
return 0;
}
View Code

## H .货物种类

sol：关键是差分，然后我是用map来维护的

• 差分
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MAXN = 1e5 + 10;
map<int, int> pre[MAXN], now;
int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int l, r, d;
scanf("%d%d%d", &l, &r, &d);
pre[l][d] ++;
pre[r + 1][d] --;
}
int res, cnt = 0;
for (int i = 1; i <= n; i++) {
for (auto it : pre[i]) {
now[it.first] += it.second;
if (now[it.first] == 0)
now.erase(it.first);
}
if (now.size() > cnt) {
cnt = now.size();
res = i;
}
}
printf("%d\n", res);
return 0;
}
View Code

## J .计算A + B

sol：skipped的情况有'+'在最前面，'+'在最后面，'+'的次数不为1。剩下的就是高精度了。反正我是用python水过去的，python大数和split真香。至于C++，之后再补上吧。

• python大数
t = int(input())
for i in range(t) :
n = input().split('+')
if len(n) != 2 or n[0] == '' or n[1] == '':
print('skipped');
else :
print(int(n[0]) + int(n[1]))
View Code

ps：一血的代码太精华了，佩服佩服，贴个传送门

--------------------------------------------------前来填坑--------------------------------------------------

• 高精度模拟
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MAXN = 10010;
struct BigInt {
const static int mod = 10000;
const static int dlen = 4;
int a[600], len;
BigInt() {
memset(a, 0, sizeof(a));
len = 1;
}
BigInt(const char* s) {
memset(a, 0, sizeof(a));
int l = strlen(s); len = 0;
for (int i = l - 1; i >= 0; i -=  dlen) {
int tmp = 0, start = max(0, i - 4 + 1);
for (int j = start; j <= i; j++)
tmp = tmp * 10 + (s[j] ^ '0');
a[len ++] = tmp;
}
}
friend BigInt operator + (BigInt a, BigInt b) {
BigInt res;
res.len = max(a.len, b.len);
int tmp = 0;
for (int i = 0; i < res.len; i++) {
tmp += a.a[i] + b.a[i];
res.a[i] = tmp % mod;
tmp /= mod;
}
if (tmp) res.a[res.len ++] = tmp;
return res;
}
void output() {
printf("%d", a[len - 1]);
for (int i = len - 2; i >= 0; i--)
printf("%04d", a[i]);
puts("");
}
};
char s[MAXN];
int find_plus(const char* s) {
int res = -1;
for (int i = 0; s[i]; i++) {
if (s[i] == '+') {
if (res != -1) return -1;
else res = i;
}
}
return res;
}
int main() {
int t; scanf("%d", &t);
while (t--) {
scanf("%s", s);
int index = find_plus(s);
if (index == -1 || index == 0 || s[index + 1] == '\0') {
puts("skipped");
} else {
s[index] = '\0';
BigInt a(s), b(s + index + 1);
BigInt res = a + b;
res.output();
}
}
return 0;
}
View Code

仿照kuangbin大佬的模板代码自己写了一个比较骚的高精度。中间写错了两次。看样子还是很有必要写这份C++版的。

posted @ 2020-02-23 22:22  Angel_Demon  阅读(...)  评论(...编辑  收藏