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;
}
作者:cherish.
出处:https://home.cnblogs.com/u/cherish-/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。