AtCoder Beginner Contest 198[C-E]
AtCoder Beginner Contest 198
The competition link is here
Question A and B is too easy, so i won't write the editorial.
C - Compass Walking
Problem Statement
You are standing at the origin of a two-dimensional plane. For each step you can move to a point whose your distance from you current position is exactly \(R\) (the coordinate of the destination of a move do not have to be intergers), find the minimum number of steps you has to take before reaching \((X, Y)\).
Constraints
-
\(1 \le R \le 10^5\)
-
\(0 \le X, Y \le 10^5\)
-
\((X,Y) \neq (0, 0)\)
-
All values in input are integers
Solution
好吧,还是写中文博客比较快。这题就是要考虑一个特殊情况。
分两种情况考虑,显然是走两点之间的直线上,不妨设距离为\(dist\):
-
恰好走完:\(dist \% R == 0\), 则直接除即可,\(ans = dist/R\)
-
不能恰好走完:
- \(dist > R\), 向上取整即可,考虑最后一步无法恰好达到则需要转为两步,\(ans=\lceil dist/R \rceil\)
- \(dist < R\), 特判为\(2\),至少需要两次。
Code
using ll = long long;
void solve(){
ll r, x, y;
std::cin >> r >> x >> y;
ll ans = ceil(sqrt(x * x + y * y) / r);
if (x * x + y * y < r * r) ans = 2;
std::cout << ans << "\n";
}
D - Send More Money
Problem Statement
给定三个字符串\(S_1, S_2, S_3\),要求\(S_1 + S_2 = S_3\)。要求给出\(N_1, N_2, N_3\), 满足:
- \(N_1 + N_2 = N_3\)
- 每个字母代表且仅代表一个数字,同理数字也只代表最多一个。
- 不能有前导零
Constraints
-
Each of \(S_1, S_2, S_3\) is a string of length between \(1\) and \(10\) (inclusive) consisting of lowercase English letters.
Solution
比赛的时候没写出来,显然多于\(10\)个字母就直接没有解。少于\(10\)个的直接用next_permutation
暴力找,再特判前导零即可。
Code
void bad(){
std::cout << "UNSOLVABLE\n";
exit(0); // 直接退出
}
void solve(){
vt<string> s(3);
rep (i, 0, 3) std::cin >> s[i];
map<char, int> mp;
for (auto v: s){
for (auto c: v) ++ mp[c];
}
if (mp.size() > 10) bad();
int m = mp.size();
string tar = "";
vt<int> num(10);
iota(all(num), 0);
for (auto e: mp) tar += e.first;
auto get_val = [&](char ch){
rep (i, 0, m){
if (ch == tar[i]) return num[i];
}
return -1ll;
};
do {
if (get_val(s[0].front()) == 0 or get_val(s[1].front()) == 0 or get_val(s[2].front()) == 0) continue;
int x1(0), x2(0), x3(0);
for (auto ch: s[0]){
x1 *= 10;
x1 += get_val(ch);
}
for (auto ch: s[1]){
x2 *= 10;
x2 += get_val(ch);
}
for (auto ch: s[2]){
x3 *= 10;
x3 += get_val(ch);
}
if (x1 + x2 == x3){
std::cout << x1 << "\n";
std::cout << x2 << "\n";
std::cout << x3 << "\n";
return;
}
} while (next_permutation(all(num)));
std::cout << "UNSOLVABLE\n";
}
E - Unique Color
Problem Statement
每个点有自己的颜色,给一颗树,并定义好的点为:
- 从点1到该点的最短路径中不存在重复颜色则为好的点。
请找到所有好的点。
Constraints
- \(2≤N≤10^5\)
- \(1≤Ci≤10^5\)
- \(1≤Ai,Bi≤N\)
- The given graph is a tree.
- All values in input are integers.
Solution
这题WA
了几发,没看清楚题目。
由于这个是树结构,则一次从结点\(1\)的dfs
就可以找到最短路径。(假如是带权图等,我们可以用基于heap
的dijkstra
并记录路径便可以保证时间复杂度。)需要注意的是,我们并不能简单的记录路径上某个颜色是否用过。我们应该记录颜色的数量,否则我们可能会误判,因为dfs
访问之后需要进行回溯,所以假如用0-1变量的话直接清空会导致误判没有改颜色,实际上我们应该用++
和–
进行处理。
Code
const int maxn = 1e5 + 50;
vt<int> E[maxn];
int color[maxn], use[maxn];
void solve(){
mst(use, 0);
int n; std::cin >> n;
rep (i, 1, n + 1) std::cin >> color[i];
rep (i, 0, n + 1) E[i].clear();
rep (i, 0, n - 1){
int u, v; std::cin >> u >> v;
E[u].pb(v), E[v].pb(u);
}
vt<int> ans;
function<void(int, int)> dfs = [&](int cur, int fa){
if (!use[color[cur]]) ans.pb(cur);
++use[color[cur]]; // 增加访问
for (auto go: E[cur]){
if (go == fa) continue;
dfs(go, cur);
--use[color[go]]; // 访问结束
}
};
dfs(1, 0);
sort(all(ans));
for (auto x: ans) std::cout << x << "\n";
}