Atcoder beginer contest 237 problem solution

Posted by dupreelove on Wed, 02 Feb 2022 21:58:44 +0100

AtCoder Beginner Contest 237

A - Not Overflow

Title Description: give you an integer in the range of long long and judge whether it is in the range of int.

Idea: simulate according to the meaning of the topic

Time complexity: \ (O(1) \)

Reference code:

void solve() {
	long long n;
	cin >> n;
	if (n >= INT_MIN && n <= INT_MAX) cout << "Yes" << '\n';
	else cout << "No" << '\n';
	return;
}

B - Matrix Transposition

Title Description: give you A \ (n \times m \) matrix \ (A \) and output \ (A^T \).

Idea: simulate according to the meaning of the topic.

Time complexity: \ (O(nm) \)

Reference code:

void solve() {
	int n, m;
	cin >> n >> m;
	vector<vector<int>>a(n + 1, vector<int>(m + 1, 0));
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) cin >> a[i][j];
	}
	for (int j = 1; j <= m; ++j) {
		for (int i = 1; i <= n; ++i) cout << a[i][j] << ' ';
		cout << '\n';
	}
	return;
}

C - kasaka

Title Description: give you a string \ (s \), and ask if you can change the string into a palindrome string by adding the character a in front of \ (s \).

Idea: delete the same number of characters a on both sides of the string \ (s \), and then delete the redundant character a on the right to judge whether the remaining string is palindrome.

Time complexity: \ (O(n) \)

Reference code:

void solve() {
	string s;
	cin >> s;
	int n = s.size();
	string t = s;
	reverse(t.begin(), t.end());
	if (s == t) {
		cout << "Yes" << '\n';
		return;
	}
	int lr = 0, rs = n - 1;
	while (lr < rs && s[lr] == s[rs] && s[rs] == 'a') ++lr, --rs;
	while (lr < rs && s[rs] == 'a') --rs;
	t = s.substr(lr, rs - lr + 1);
	s = t;
	reverse(t.begin(), t.end());
	if (s == t) {
		cout << "Yes" << '\n';
		return;
	}
	cout << "No" << '\n';
	return;
}

D - LR insertion

Title Description: there is a set \ (S \), initially there are only elements \ (0 \), now you need to put \ (1 \sim n \) in turn. When you put the \ (i \) number, you will be told a command, indicating whether to put the \ (i \) number to the left or right of the \ (i - 1 \) number, so that you can output the final sequence.

Idea: for obvious linked list operation, you can use array to simulate linked list. Of course, note that the \ (i \) number is only related to the \ (i - 1 \) number, and it is either placed on its left or on its right. Abstracted into a tree structure, it is a binary tree, so the sequence is equivalent to the ordinal traversal of the binary tree.

Time complexity: \ (O(n) \)

Array simulation linked list:

void solve() {
	int n;
	cin >> n;
	string s;
	cin >> s;
	s = ' ' + s;
	vector<vector<int>>res(n + 1, vector<int>(2, -1));
	for (int i = 1; i <= n; ++i) {
		if (s[i] == 'L') {
			int dx = res[i - 1][0];
			if (dx != -1) {
				res[dx][1] = i;
				res[i][0] = dx;
			}
			res[i][1] = i - 1;
			res[i - 1][0] = i;
		}
		else {
			int dx = res[i - 1][1];
			if (dx != -1) {
				res[dx][0] = i;
				res[i][1] = dx;
			}
			res[i][0] = i - 1;
			res[i - 1][1] = i;
		}
	}
	int head = 0;
	for (int i = 0; i <= n; ++i) {
		if (res[i][0] != -1) continue;
		head = i;
		break;
	}
	while (head != -1) {
		cout << head << ' ';
		head = res[head][1];
	}
	cout << '\n';
	return;
}

Middle order traversal:

void solve() {
	int n;
	cin >> n;
	vector<vector<int>>a(n + 2, vector<int>(2, 0));
	string s;
	cin >> s;
	for (int i = 1; i <= n; ++i) {
		if (s[i - 1] == 'L') a[i][0] = i + 1;
		else a[i][1] = i + 1;
	}
	auto dfs = [&](auto dfs, int u)->void {
		if (a[u][0] != 0) dfs(dfs, a[u][0]);
		cout << u - 1 << ' ';
		if (a[u][1] != 0) dfs(dfs, a[u][1]);
		return;
	};
	dfs(dfs, 1);
	cout << '\n';
	return;
}

E - Skiing

Title Description: there is \ (n \) mountain number \ (1 \sim n \), and the \ (I \) mountain has a height \ (h_i \). There are \ (m \) cable bridges connecting some mountains. These cable bridges are two-way. If the two mountains are numbered \ (x, y \) from the high mountain to the low mountain, the value \ (h_x - h_y \) can be obtained; If you go from a low mountain to a high mountain, you get a value of \ (2 (h_x - h_y) (h_x < h_y) \). You have the initial value \ (0 \), and then start from mountain \ (1 \), you can end at any mountain and ask the maximum value you can finally get.

Idea: we can assume that the positive side is positive weight and the reverse side is negative weight. We can use BFS, and then ensure that each mountain is visited at least once, and then use greater value to update the current point in the subsequent extensive search. Finally, traverse all points to get the maximum value of their value.

Time complexity: \ (O(n + m) \)

Reference code:

void solve() {
	int n, m;
	cin >> n >> m;
	vector<vector<int>>graph(n + 1);
	vector<int>H(n + 1, 0);
	for (int i = 1; i <= n; ++i) cin >> H[i];
	int u, v;
	vector<long long>dis(n + 1, 0);
	vector<bool>vis(n + 1, 0);
	for (int i = 1; i <= m; ++i) {
		cin >> u >> v;
		graph[u].push_back(v);
		graph[v].push_back(u);
	}
	queue<int>q;
	q.push(1);
	vis[1] = true;
	while (!q.empty()) {
		u = q.front();
		q.pop();
		for (auto v : graph[u]) {
			long long dx = dis[u] + (H[u] >= H[v] ? H[u] - H[v] : 2ll * (H[u] - H[v]));
			if (vis[v] == false) dis[v] = dx, vis[v] = true, q.push(v);
			if (dis[v] < dx) {
				dis[v] = dx;
				q.push(v);
			}
		}
	}
	long long res = 0;
	for (int i = 1; i <= n; ++i) res = max(res, dis[i]);
	cout << res << '\n';
	return;
}

F - |LIS| = 3

Topic Description: you need to construct an array \ (a \) with a length of \ (n \) with LIS = 3, and meet \ (1 \leq a_i \leq m \) for any \ (a_i \). Ask the number of such \ (a \) schemes. Take the mold of 998244353.

Data range: \ (3 \ Leq n \ Leq 1000, 3 \ Leq m \ Leq 10 \).

Idea: for the obvious dp, the definition status \ (f_{i, J, K, R} \) indicates that for the first \ (I \) numbers, LIS is the number of schemes of subset (J, K, R). The transfer equation is:

\[\begin{align} f_{i , j , k , r} & = \sum\limits_{x = 0}^{j}f_{i - 1, x , k , r} + \sum\limits_{x = j + 1}^{k}f_{i - 1 , j , x , r} + \sum\limits_{x = k + 1}^{r} f_{i-1 , j , k , x} \end{align} \]

Initial condition \ (f_{0, m, m, m} = 1 \).

The final answer is:

\[\sum\limits_{i = 0}^{m - 1}\sum\limits_{j = 0}^{m - 1}\sum\limits_{k = 0}^{m - 1} f_{n , i , j , k} \]

Time complexity: \ (O(nm^4) \)

Reference code:

const int mod = 998244353;
void solve() {
	int n, m;
	cin >> n >> m;
	vector<vector<vector<vector<int>>>>f(n + 1, vector<vector<vector<int>>>(m + 1, vector<vector<int>>(m + 1, vector<int>(m + 1, 0))));
	f[0][m][m][m] = 1;
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j <= m; ++j) {
			for (int k = 0; k <= m; ++k) {
				for (int r = 0; r <= m; ++r) {
					int dx = f[i][j][k][r];
					if (dx == 0) continue;
					for (int x = 0; x < m; ++x) {
						if (x <= j) f[i + 1][x][k][r] = (f[i + 1][x][k][r] + dx) % mod;
						else if (x <= k) f[i + 1][j][x][r] = (f[i + 1][j][x][r] + dx) % mod;
						else if (x <= r)f[i + 1][j][k][x] = (f[i + 1][j][k][x] + dx) % mod;
					}
				}
			}
		}
	}
	int res = 0;
	for (int i = 0; i < m; ++i)
		for (int j = 0; j < m; ++j)
			for (int k = 0; k < m; ++k)
				res = (res + f[n][i][j][k]) % mod;
	cout << res << '\n';
	return;
}

G - Range Sort Query

Title Description: give you an arrangement \ (P \) with a length of \ (n \), with \ (m \) operations. Each operation gives you three numbers op lr rs. The meaning is as follows:

  • op = 1 means that the elements in the interval [LR, RS] are arranged in ascending order
  • op = 2 means that the elements in the interval [LR, RS] are arranged in descending order

Finally, ask the subscript of the position where the element \ (x \) is located. (subscripts are numbered from \ (1 \).

Idea: this question is related to P2824 [HEOI2016/TJOI2016] sort There is no difference in the description of the topic. Considering the inquiry of this topic, we need to find an online solution. We found a blog during the game HEOI2016/TJOI2016] sort The code in has been magic modified. Related to the merging and splitting of line segment trees, you can find relevant blogs to learn.

Time complexity: \ (O((n + m)logn + nlogn) \) the last \ (nlogn \) is the worst complexity required to solve the answer

Reference code:

#include<bits/stdc++.h>
using ll = long long;
const int maxn = 300010;

struct Tree {
	Tree* ls, * rs;
	int l, r, v;
	Tree() {
		ls = rs = NULL;
		l = r = v = 0;
	}
	inline void pushup() { if (this->l != this->r) this->v = (this->ls ? this->ls->v : 0) + (this->rs ? this->rs->v : 0); else this->v = 1; }
};

struct OP {
	int l, r;
	bool up;
	Tree* rot;

	inline bool operator<(const OP& _others) const {
		return this->r < _others.r;
	}

	OP(int _l = 0, int _r = 0, bool _up = 0, Tree* _rot = 0) {
		l = _l; r = _r; up = _up; rot = _rot;
	}
};
OP temp;
std::set<OP>s;

int n, m;
int MU[maxn];

void split(int, bool);
void insert(Tree*, int, int, int);
void split(Tree*, Tree*, Tree*, int);
Tree* merge(Tree*, Tree*);
int query(Tree*, int);

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	using std::cin;
	using std::cout;
	int x;
	cin >> n >> m >> x;
	for (int i = 1; i <= n; ++i) {
		auto _rot = new Tree;
		cin >> MU[i];
		insert(_rot, 1, n, MU[i]); s.insert(OP(i, i, true, _rot));
	}
	for (int j = 1, a, b, c; j <= m; ++j) {
		cin >> a >> b >> c;
		--a;
		split(b, true); split(c + 1, false);
		auto l = s.lower_bound({ 0, b, true, NULL }), r = s.lower_bound({ 0, c + 1, true, NULL });
		auto _tmp = *l;
		for (auto i = s.erase(l); i != r; i = s.erase(i)) {
			_tmp.rot = merge(_tmp.rot, (*i).rot);
		}
		_tmp.l = b; _tmp.r = c; _tmp.up = !a;
		s.insert(_tmp);
	}
	for (int i = 1; i <= n; ++i) {
		int q = i;
		auto _ans = s.lower_bound({ 0, q, true, NULL }); auto ans = *_ans;
		int k = ans.up ? q - ans.l + 1 : ans.r - q + 1;
		q = query(ans.rot, k);
		if (q == x) {
			cout << i << '\n';
			return 0;
		}
	}
	return 0;
}
int query(Tree* u, int k) {
	if (u->l == u->r) return u->l;
	if (!u->ls) return query(u->rs, k);
	if (u->ls->v >= k) return query(u->ls, k);
	return query(u->rs, k - u->ls->v);
}

Tree* merge(Tree* u, Tree* v) {
	if (!u) return v; else if (!v) return u;
	u->v += v->v;
	u->ls = merge(u->ls, v->ls);
	u->rs = merge(u->rs, v->rs);
	return u;
}

void insert(Tree* u, int l, int r, int v) {
	++u->v;
	if ((u->l = l) == (u->r = r)) return;
	int mid = (l + r) >> 1;
	if (v <= mid) insert(u->ls = new Tree, l, mid, v);
	else insert(u->rs = new Tree, mid + 1, r, v);
}

void split(int x, bool isfront) {
	auto k = s.lower_bound({ 0, x, true, NULL }); if (k == s.end()) return; auto t = *k;
	if (t.l == x) return;
	s.erase(k);
	int _k = (isfront ? t.r - x + 1 : x - t.l), len = t.r - t.l + 1;
	if (t.up == isfront) {
		Tree* _rot = new Tree;
		_k = len - _k;
		if (!_k) {
			s.insert(t); return;
		}
		split(t.rot, t.rot, _rot, _k);
		if (!t.up) {
			_k = len - _k; std::swap(_rot, t.rot);
		}
		s.insert({ t.l, t.l + _k - 1, t.up, t.rot });
		s.insert({ t.l + _k, t.r, t.up, _rot });
	}
	else {
		Tree* _rot = new Tree;
		if (!_k) {
			s.insert(t); return;
		}
		split(t.rot, t.rot, _rot, _k);
		if (!t.up) {
			std::swap(t.rot, _rot); _k = len - _k;
		}
		s.insert({ t.l, t.l + _k - 1, t.up, t.rot });
		s.insert({ t.l + _k, t.r, t.up, _rot });
	}
}

void split(Tree* u, Tree* l, Tree* r, int k) {
	l->l = r->l = u->l; r->r = l->r = u->r;
	if (!u->ls) split(u->rs, l->rs ? l->rs : l->rs = new Tree, r->rs ? r->rs : r->rs = new Tree, k);
	else if (k == u->ls->v) {
		l->ls = u->ls; r->rs = u->rs; l->rs = NULL; r->ls = NULL;
	}
	else if (k < u->ls->v) {
		split(u->ls, l->ls ? l->ls : l->ls = new Tree, r->ls ? r->ls : r->ls = new Tree, k);
		r->rs = u->rs; l->rs = NULL;
	}
	else {
		split(u->rs, l->rs ? l->rs : l->rs = new Tree, r->rs ? r->rs : r->rs = new Tree, k - u->ls->v);
		l->ls = u->ls; r->ls = NULL;
	}
	l->pushup(); r->pushup();
}

Topics: ABC