--- tags: Programming Contest --- # AtCoder Beginner Contest 180 題解 [題目連結](https://atcoder.jp/contests/abc180) ## 心得 賽後才來寫的,這場比賽跟 cf 連在一起,所以就沒打這場了。 ## A, B, C 都是水題。 聽說第二題會卡 double,得用 long double 才會過,用 python 的表示有這回事嗎 ¯\(°_o)/¯ ## D. Takahashi Unevolved 一開始我的想法是 greedy,看第一種操作還是第二種操作產出來的數字小就用哪種,但這樣會 TLE。重新看題目發現 A >= 2 這個條件,這代表說我如果全部都用第一種,那時間是 O(lgY)。 於是我的想法修正成:一次第一種操作等價於(最多)幾次第二種操作?假設是 k 次,只要 k >= 1 那代表我用 k 次第二種操作比較好,要不然還是用一次第一種操作。我不斷重覆上述流程,直到 X 再也不能更大為止。 k 可以透過解不等式 $X + kB \le X \cdot A$ 求得,小心別讓 $X + kB \ge Y$ 了(也就是說要保證 $X + kB < Y$)。 ```python X, Y, A, B = map(int, input().split()) ans = 0 while True: if min(X * A, X + B) >= Y: break k = (min(X * A, Y - 1) - X) // B if k >= 1: X = X + k * B ans += k else: X = X * A ans += 1 print(ans) ``` AC 後看了其他人的 code 才發現有「一定會先用第一種操作才會用第二種操作」這樣的性質。 ## E. Traveling Salesman among Aerial Cities 第二筆測資的另一個答案為 [1, 2, 3, 1],不需要走到一個城市多次。因為給定的距離函式且足三角不等式 $dist(city_u, city_v) \le dist(city_u, city_k) + dist(city_k, city_v)$,所以這題等價標準的 TSP。若不滿足的話,我們得先 floyd warshall 把城市之間的最短距離找出來再跑 TSP。 我個人習慣的 TSP 寫法是用 bitmask dp 求出 Hamiltonian Path,最後再看看「停在城市 $v$ 的 Hamiltonian Path 加上從該城市到起始點的距離」的最小值是多少。 設 $dp[S, v]$ 代表我們走過的城市集合是 $S$,且我們最後停在城市 $v$ 的 minimum cost。考慮城市 $v$ 的上一個城市 $u$ 是那些,即我們是從哪些城市走過來的,我們可以得到以下轉移方程: $$ dp[S, v] = \min_{u \in S} dp[S - \{v\}, u] + dist(city_u, city_v) $$ 其中 $-$ 是集合的差運算。 該 dp 的初使化為每項都是無窮大,除了 $dp[\{1\}, 1] = 0$,因為我們一開始就在城市 1。 「停在城市 $v$ 的 Hamiltonian Path」就是 $dp[\{1, 2, \cdots, N\}, v]$,如果此值再加上城市 $v$ 到城市 $1$ 的距離 $dist(city_v, city_1)$,那就是對應的 Hamiltonian Cycle。 於是題目所求就是: $$ \min_v dp[\{1, 2, \cdots, N\}, v] + dist(city_v, city_1) $$ 實作上使用 0-based index,且用 bitmask 來表示集合,整體時間 $O(2^N \cdot N^2)$。 使用 c++ 或 pypy 都可以過,以下給出 c++ 的程式碼。 ```cpp #include <algorithm> #include <iostream> #include <tuple> #include <vector> using namespace std; using ll = long long; using City = tuple<ll, ll, ll>; ll dist(City city1, City city2) { auto [a, b, c] = city1; auto [p, q, r] = city2; return abs(p - a) + abs(q - b) + max(0ll, r - c); } int main() { ios::sync_with_stdio(false); cin.tie(0); int N; cin >> N; vector<City> cities; for (int i = 0; i < N; i++) { ll x, y, z; cin >> x >> y >> z; cities.push_back({x, y, z}); } const ll inf = 1e15; auto dp = vector<vector<ll>>(1 << N, vector<ll>(N, inf)); dp[1 << 0][0] = 0; for (int s = 1; s < (1 << N); s++) { for (int v = 0; v < N; v++) { if (s & (1 << v)) { for (int u = 0; u < N; u++) { if (s & (1 << u)) { ll val = dp[s ^ (1 << v)][u] + dist(cities[u], cities[v]); dp[s][v] = min(dp[s][v], val); } } } } } ll ans = inf; for (int v = 0; v < N; v++) { ans = min(ans, dp[(1 << N) - 1][v] + dist(cities[v], cities[0])); } cout << ans << endl; return 0; } ``` :::success [< 回到所有題解](https://hackmd.io/@amoshyc/HkWWepaPv/) :::