# AtCoder Beginner Contest 176 Tutorial
# Problem A - Takoyaki (opens new window)
The time needed equals to .
Code (Python3)
n, x, t = map(int, input().split(' '))
print(((n - 1) // x + 1) * t)
2
# Problem B - Multiple of 9 (opens new window)
Let , since , we have . So we just need to check the sum of all the digits of .
Code (Python3)
print('Yes' if sum(map(int, input())) % 9 == 0 else 'No')
# Problem C - Step (opens new window)
Just greedily increase current number to the maximum to its left, and then update the maximum if current number is larger than it.
Code (C++)
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
int main() {
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; ++i)
cin >> a[i];
int hi = 0;
ll ans = 0;
for (int i = 1; i <= n; ++i) {
ans += max(0, hi - a[i]);
hi = max(hi, a[i]);
}
cout << ans;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Problem D - Wizard in Maze (opens new window)
It's a very typical - BFS, since the cost is if we go along the roads, while the cost is if we cast a magic spell.
Compared to ordinary BFS, we need to use a deque instead of a single-ended queue. For relaxations that cost , we do push_front
, while for those cost , we do push_back
. In this way, the elements in the deque are kept in an non-decreasing order, which means we will happily take the current value as the optimal value when we first reach the target position.
Code (C++)
#include <deque>
#include <iostream>
#include <vector>
#define INF 0x3f3f3f3f
using namespace std;
const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, -1, 0, 1};
int h, w, sx, sy, ex, ey;
int main() {
cin >> h >> w >> sx >> sy >> ex >> ey;
sx--, sy--, ex--, ey--;
vector<string> a(h);
for (int i = 0; i < h; ++i)
cin >> a[i];
vector<vector<int>> dist(h, vector<int>(w, INF));
vector<vector<bool>> vis(h, vector<bool>(w, false));
deque<pair<int, int>> q;
q.push_back({sx, sy});
dist[sx][sy] = 0;
while (!q.empty()) {
auto f = q.front();
q.pop_front();
int ci = f.first, cj = f.second;
if (ci == ex && cj == ey) {
cout << dist[ci][cj];
return 0;
}
if (vis[ci][cj])
continue;
vis[ci][cj] = true;
for (int k = 0; k < 4; ++k) {
int ni = ci + dy[k], nj = cj + dx[k];
if (ni < 0 || ni >= h || nj < 0 || nj >= w ||
dist[ni][nj] <= dist[ci][cj] || a[ni][nj] == '#')
continue;
dist[ni][nj] = dist[ci][cj];
q.push_front({ni, nj});
}
for (int ni = ci - 2; ni <= ci + 2; ++ni)
for (int nj = cj - 2; nj <= cj + 2; ++nj) {
if (ni < 0 || ni >= h || nj < 0 || nj >= w || a[ni][nj] == '#' ||
dist[ni][nj] <= dist[ci][cj] + 1)
continue;
dist[ni][nj] = dist[ci][cj] + 1;
q.push_back({ni, nj});
}
}
cout << -1;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# Problem E - Bomber (opens new window)
First, we can simply count how many targets there are in each row and each column.
Supposing the maximum of rows is , and for columns. It is obvious that we can never achieve any value greater than . In addition, we may not achieve because there might be a target at the crossing point of the row and the column, in which case this target is counted twice. So our worst case value is if we choose a row from those having , and a column from those having . Since all other choices cannot give better results, we only need to consider these rows and columns.
There might still be a log of combinations (worst case ). However, we do not need to check these combinations one by one. We can consider it from the perspective of targets. Say there are rows of and columns of , if the number of target is smaller than , then it is ensured than there is at least one combination which will give us . Otherwise, there are not so many combinations, so we can check them one by one, until we find a combination giving , or we finish all the combinations and none is suitable, then we will have instead.
Code (C++)
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int main() {
int h, w, m;
cin >> h >> w >> m;
vector<int> hc(h + 1), wc(w + 1);
vector<pair<int, int>> p(m);
for (int i = 0; i < m; ++i)
cin >> p[i].first >> p[i].second, hc[p[i].first]++, wc[p[i].second]++;
set<pair<int, int>> s(p.begin(), p.end());
int hm = *max_element(hc.begin(), hc.end());
int wm = *max_element(wc.begin(), wc.end());
vector<int> vh, vw;
for (int i = 1; i <= h; ++i)
if (hc[i] == hm)
vh.emplace_back(i);
for (int i = 1; i <= w; ++i)
if (wc[i] == wm)
vw.emplace_back(i);
int sh = vh.size(), sw = vw.size();
if (sh * sw > m) {
cout << hm + wm;
return 0;
}
for (int i : vh)
for (int j : vw)
if (!s.count({i, j})) {
cout << hm + wm;
return 0;
}
cout << hm + wm - 1;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Problem F - Brave CHAIN (opens new window)
There is an obvious DP idea, in which we maintain states , meaning the maximum we can get when we choose to keep numbers (not indices) and . But this is not enough to pass.
Do we always need to update all the states? For each segment of length , only a few of all states can be updated, because we are only given at most different numbers, which means we do not have many choices.
So, how to do state transitions? Supposing we are considering .
- If , then we should choose them all. In this case, instead of updating states, we should keep the number of such triplets in a separate variable. So the transition is .
- We change the current reserved numbers to two of , e.g., . In this case, we have two further choices
- Make no triplets, and update to current global optimal value .
- Make a triplet using two reserved and current , then update to . The transition is .
- We change one of the reserved number to one of , e.g., . In this case, we need to enumerate the other reserved number , and we have two further choices
- Make no triplets, and update to local optimal value , which means the best value we can get when we reserve at least one .
- Particularly, if , then we can update to The transition is
So the overall time complexity becomes , which is acceptable. It should be noted that all these updates should not be applied instantly. Instead, we store them and apply them at last.
During the update , we need to update
- Global optimum
- Local optimum , and
- State , and
After all these, we still have not handled the last number . So we need to compare and . After that, we add to the number of natural triplets , and now we have the answer.
Code (C++)
#include <iostream>
#include <vector>
#define INF 0x3f3f3f3f
using namespace std;
typedef pair<int, int> pii;
int main() {
int n;
cin >> n;
vector<int> a(3 * n);
for (int i = 0; i < 3 * n; ++i)
cin >> a[i];
vector<vector<int>> f(n + 1, vector<int>(n + 1, -INF));
vector<int> local_opt(n + 1, -INF);
f[a[0]][a[1]] = f[a[1]][a[0]] = 0;
local_opt[a[0]] = 0, local_opt[a[1]] = 0;
vector<pair<pii, int>> updates;
int triplets = 0, opt = 0;
for (int i = 2; i < 3 * (n - 1); i += 3) {
vector<int> b(3);
for (int j = 0; j < 3; ++j)
b[j] = a[i + j];
if (b[0] == b[1] && b[0] == b[2]) {
triplets++;
continue;
}
updates.clear();
for (int p = 0; p <= 2; ++p) {
int q = (p + 1) % 3, s = (p + 2) % 3;
updates.push_back({{b[p], b[q]}, opt});
updates.push_back({{b[p], b[q]}, f[b[s]][b[s]] + 1});
for (int x = 1; x <= n; ++x) {
updates.push_back({{b[p], x}, local_opt[x]});
if (b[q] == b[s])
updates.push_back({{b[p], x}, f[x][b[q]] + 1});
}
}
for (const auto &u : updates) {
int x = u.first.first, y = u.first.second, val = u.second;
if (f[x][y] < val) {
f[x][y] = f[y][x] = val;
opt = max(opt, val);
local_opt[x] = max(local_opt[x], val);
local_opt[y] = max(local_opt[y], val);
}
}
}
opt = triplets + max(opt, f[a.back()][a.back()] + 1);
printf("%d", opt);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50