返回顶部

AtCoder Beginner Contest 235 题解

赛时做到E,看到F觉得不会就直接开摆惹

A - Rotate

题目描述:给你一个三位数,不含数字\(0\),假设这三位数用\(abc\)表示,求\(abc + bca + cab\)

思路:根据题目描述模拟即可

时间复杂度:\(O(1)\)

参考代码:

void solve() {
	string s;
	cin >> s;
	auto f = [&](int a, int b, int c) {
		return a * 100 + b * 10 + c;
	};
	int res = f(s[0] - '0', s[1] - '0', s[2] - '0');
	res += f(s[1] - '0', s[2] - '0', s[0] - '0');
	res += f(s[2] - '0', s[0] - '0', s[1] - '0');
	cout << res << '\n';
	return;
}

B - Climbing Takahashi

题目描述:给你长度为\(n\)的数组\(a\),求最大的\(i\)使得\(a_{j - 1} < a_j\;\forall 1\leq j \leq i\),特别的\(a_0 = 0\)

数据范围:\(2 \leq n \leq 10^5 , 1 \leq a_i \leq 10^9\)

思路:根据题意模拟即可

时间复杂度:\(O(n)\)

参考代码:

void solve() {
	int n(0), h(0);
	int res = 0;
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		cin >> h;
		if (h > res) res = h;
		else break;
	}
	cout << res << '\n';
	return;
}

C - The Kth Time Query

题目描述:给你一个长度为\(n\)的数组\(A\),给你\(Q\)个询问,每次询问\((x , k)\)表示数字\(x\)\(A\)中第\(k\)次出现的位置。若\(k\)大于\(x\)的数量或者\(A\)中不存在整数\(x\)输出\(-1\)

思路:考虑到\(A_i\)比较大,使用unordered_map映射一下再使用vector存储一下下标即可。

时间复杂度:\(O(n + q)\)

参考代码:

unordered_map<int, vector<int>>mp;
void solve() {
	int n(0), q(0), a;
	cin >> n >> q;
	for (int i = 1; i <= n; ++i) {
		cin >> a;
		mp[a].push_back(i);
	}
	int x(0), k(0);
	while (q--) {
		cin >> x >> k;
		if (mp.count(x) == 0 || mp[x].size() < k) cout << "-1\n";
		else cout << mp[x][k - 1] << '\n';
	}
	return;
}

D - Multiply and Rotate

题目描述:给你两个整数\(a , n\),初始时你有一个整数\(x = 1\),每次你可以将当前数字乘以\(a\)\(x = x * a\),或者在满足\(x\geq 10 \&\& x \% 10!= 0\)时,将最低位的数字变成最高位,比如123,进行该操作后变成312。问将\(x\)变为\(n\)的最小操作次数,若无法实现,输出-1

数据范围:$2\leq a , n < 10^6 $

思路:考虑BFS进行求解即可,注意过程中\(a * x\)可能超过int的表示范围,所以需要开long long或者特判一下。

时间复杂度:\(O(10^6)\)(因为得到的数字个数不超过\(10^6\)

参考代码:

struct Node {
	long long val;
	int step;
	Node(long long _val = 0 , int _step = 0):val(_val) , step(_step){}
};
void solve() {
	int a(0), n(0);
	cin >> a >> n;
	auto f = [](string s) {
		int ans = 0, len = s.size();
		ans = s.back() - '0';
		for (int i = 0; i < len - 1; ++i) ans = ans * 10 + s[i] - '0';
		return ans;
	};
	queue<Node> q;
	q.push({ 1ll , 0 });
	int res = -1, cnt = 0;
	vector<bool>vis(1000005, false);
	while (!q.empty()) {
		auto [val, step] = q.front();
		q.pop();
		vis[val] = true;
		long long dx = 1ll * val * a;
		if (dx == n) {
			res = step + 1;
			break;
		}
		if (dx <= 1000000 && vis[dx] == false) {
			vis[dx] = true;
			q.push({ dx , step + 1 });
		}
		if (val >= 10 && val % 10 != 0) {
			dx = f(to_string(val));
			if (dx <= 1000000 && vis[dx] == false) {
				if (dx == n) {
					res = step + 1;
					break;
				}
				q.push({ dx , step + 1 });
				vis[dx] = true;
			}
		}
	}
	cout << res << '\n';
	return;
}

E - MST + 1

题目描述:给你一个带权无向图\(G\),可能存在重边和自环,该图的边权两两不同。给你\(Q\)个询问,每次询问给你一条边\(e_i\),问若将\(e_i\)加入图\(G\)中,新图的最小生成树是否含有边\(e_i\),若含有输出Yes,否则输出No。注意\(e_i\)的边权与原图中的边权也不同。

思路:我们先求出原图\(G\)的最小生成树,那么对于每次询问就是若加上该条边,就构成了一个环,而要变成树,需要删除其中的一条边,考虑到是最小生成树,所以删除的是权最大的边。所以我们先将原图的最小生成树\(T\)求出来,然后对于每次询问\(e_i = (u_i , v_i , w_i)\),我们求\(T\)上路径\((u_i , v_i)\)的最大边权,若最大边权大于\(w_i\)则输出Yes,否则输出No。对于求路径最大边权,我使用了树链剖分,码量有点大,可以选用其他方法如:倍增。

时间复杂度:\(O(qlog^2n + mlogm)\)

参考代码:

const int N = 2e5 + 5;
struct Edge {
	int u, v, w;
	Edge(int _u = 0, int _v = 0, int _w = 0):u(_u) , v(_v) , w(_w){}
	bool operator < (const Edge& a)const {
		return w < a.w;
	}
};
struct Node {
	int v, w;
	Node(int _v , int _w):v(_v) , w(_w){}
};
vector<vector<Node>>graph(N);
int a[N];
int fa[N], dep[N], siz[N], son[N];
void dfs1(int u, int f) {
	fa[u] = f; dep[u] = dep[f] + 1;
	siz[u] = 1;
	int maxsize = -1;
	for (auto g : graph[u]) {
		if (g.v == f) continue;
		a[g.v] = g.w;
		dfs1(g.v, u);
		siz[u] += siz[g.v];
		if (siz[g.v] > maxsize) maxsize = siz[g.v], son[u] = g.v;
	}
	return;
}
int tim, dfn[N], top[N], weight[N];
void dfs2(int u, int t) {
	dfn[u] = ++tim;
	top[u] = t;
	weight[tim] = a[u];
	if (!son[u]) return;
	dfs2(son[u], t);
	for (auto g : graph[u]) {
		if (g.v == fa[u] || g.v == son[u]) continue;
		dfs2(g.v, g.v);
	}
	return;
}
struct SegmentTree {
	int max, lr, rs, mid;
};
SegmentTree tree[N << 2];
void pushUp(int rt) {
	tree[rt].max = max(tree[rt << 1].max, tree[rt << 1 | 1].max);
	return;
}
void buildTree(int rt, int lr, int rs) {
	tree[rt].max = 0;
	tree[rt].lr = lr; tree[rt].rs = rs;
	if (lr == rs) {
		tree[rt].max = weight[lr];
		return;
	}
	int mid = tree[rt].mid = lr + rs >> 1;
	buildTree(rt << 1, lr, mid);
	buildTree(rt << 1 | 1, mid + 1, rs);
	pushUp(rt);
	return;
}
int query(int rt, int lr, int rs) {
	if (lr > tree[rt].rs || tree[rt].rs < lr) return 0;
	if (tree[rt].lr >= lr && tree[rt].rs <= rs) return tree[rt].max;
	int res = 0;
	if (tree[rt].mid >= lr) res = max(res, query(rt << 1, lr, rs));
	if (tree[rt].mid < rs) res = max(res, query(rt << 1 | 1, lr, rs));
	return res;
}
int queryChain(int u, int v) {
	int res = 0;
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) std::swap(u, v);
		res = max(res, query(1, dfn[top[u]], dfn[u]));
		u = fa[top[u]];
	}
	if (dep[u] > dep[v]) std::swap(u, v);
	res = max(res, query(1, dfn[u] + 1, dfn[v]));
	return res;
}
void solve() {
	vector<Edge>edges;
	int n, m, u, v, w, q;
	cin >> n >> m >> q;
	for (int i = 1; i <= m; ++i) {
		cin >> u >> v >> w;
		edges.push_back({ u , v , w });
		edges.push_back({ v , u , w });
	}
	vector<int>parent(n + 1, 0);
	for (int i = 1; i <= n; ++i) parent[i] = i;
	auto find = [&](auto find, int u)-> int{
		if (parent[u] != u) parent[u] = find(find , parent[u]);
		return parent[u];
	};
	sort(edges.begin(), edges.end());
	for (auto [u, v, w] : edges) {
		u = find(find, u); v = find(find, v);
		if (u == v) continue;
		graph[u].push_back({ v , w });
		graph[v].push_back({ u , w });
		parent[u] = v;
	}
	dfs1(1, 1);
	dfs2(1, 1);
	buildTree(1, 1, n);
	while (q--) {
		cin >> u >> v >> w;
		int res = queryChain(u, v);
		if (res < w) cout << "No" << '\n';
		else cout << "Yes" << '\n';
	}
	return;
}
posted @ 2022-01-15 21:41  cherish-lgb  阅读(199)  评论(1编辑  收藏  举报