ABC060: http://abc060.contest.atcoder.jp
ARC073: http://arc073.contest.atcoder.jp
本家の解説
【ARC073/ABC060】
— AtCoder (@atcoder) 2017年4月29日
コンテストは終了しました。ご参加ありがとうございました。
解説PDF:https://t.co/mRtuITS6X7
解説放送:https://t.co/GLCwB5ZScR
以下、解説
A. Shiritori
http://abc060.contest.atcoder.jp/submissions/1255055
C++のstringクラスのfront,backメソッドを使うと楽
B. Choose Integer
http://abc060.contest.atcoder.jp/submissions/1255056
Aの倍数を適当に足してできた数は、結局はAの倍数である。
よって、「あるAの倍数 mod B = C」を満たすかチェックすれば良い。
賢いアルゴリズムを考えるべきではあるが、AtCoderの200点は愚直にやれば解ける問題が多いので、何かしらの全探索をまず考えてみよう。
ここではAの倍数を全列挙して考えればよい。
C. Sentou
http://abc060.contest.atcoder.jp/submissions/1255057
t[i]秒にスイッチが押されてt[i+1]秒にまたスイッチが押されるとき、お湯が出続ける時間はmin(T, t[i+1]-t[i])である。
この計算は全ての区間について独立に考えることができる(延長される訳ではないので)ので、全ての区間の時間を足すと答え。
t[N]秒で押されてからT秒出るので、それを足すのを忘れないように。
オーバーフローにも気をつける。
D. Simple Knapsack
http://abc060.contest.atcoder.jp/submissions/1255058
dp[i][w0][w1][w2][w3] := i番目まで使ってw[0]の物をw0個,w[0]+1の物をw1個,w[0]+2の物をw2個,w[0]+3の物をw3個取る時の価値の最大
として、根性O(N^5)DPをする。
dp[101][101][101][101][101]とするとMLE。
よくあるメモリ領域を使いまわすDP手法を使って、dp[2][101][101][101][101]としてもMLE。
w0~w3の個数をカウントして上限ギリギリにしてやってAC。
E. Ball Coloring
http://arc073.contest.atcoder.jp/submissions/1255061
全ての要素の最大MAXと最小MINは必ずRmax,Rmin,Bmax,Bminのどれかに現れる。
赤と青で特別に分ける理由も特に無いので、以下の2つに場合分けして解く。
Rmax=MAX,Bmin=MIN(solve1関数)
赤の方はなるべく下限を大きく、青の方はなるべく上限を小さくしたいので、全てのペアに関して、大きい方を赤、小さい方を青とすればよい。
Rmax=MAX, Rmin=MIN(solve2関数)
赤の方は適当で良く、青の最大と最小の差を最小化するアルゴリズムを考える。
赤側の方は特に考える必要は無く、青の方を上手くやるようにアルゴリズムを作ろう。
まず全てのペアについて小さい方を青とする。
それから、小さい方から順番に大小を入れ替えていきながら、答えの最小値を探せば良い。
最小値最大値のセグメントツリーを用意して実装した
F. Many Moves
http://arc073.contest.atcoder.jp/submissions/1255256
公式解説の通り説明していく
O(N^3)解法
dp[i][a][b] := i番目までのクエリを終えていて、片方の駒がa,もう片方の駒がbにいる最小時間
dp[0][A][B] = 0, dp[0][?][?] = INF
dp[i + 1][X[i]][B] = min(dp[i][A][B] + |X[i] - A|)
dp[i + 1][A][X[i]] = min(dp[i][A][B] + |X[i] - B|)
で更新する
メモリがまず乗らないのでダメ
O(N^2)解法
dp[i][a] := i番目までのクエリを終えていて、片方の駒がa、もう片方の駒がX[i-1]にいる最小時間
X[-1] = Bとしておき、dp[0][A] = 0, dp[0][?] = INFが初期値
後は、aをX[i]に移すか、X[i-1]をX[i]に移すかで更新する
iの方はそのまま置くとMLEするので、使いまわすアレで使いまわす。
O(N^3)解法におけるbはb=X[i-1]であると考える
1. b(X[i - 1]) -> X[i]の遷移
dp[(i + 1) % 2][a] = min(dp[(i + 1) % 2][a], dp[i % 2][a] + abs(b - X[i]));
2. a -> X[i]の遷移
dp[(i + 1) % 2][b] = min(dp[(i + 1) % 2][b], dp[i % 2][a] + abs(a - X[i]));
O(NlogN)解法
各遷移を高速化することを考える。
遷移1はよくよく見ると、dpの全ての要素にabs(b-X[i])を足しているだけと見れる。
そして、全てに同じ数を足しても大小関係は特に変わらないので、offsetを用意しておき、そちらに累積しておく。
遷移2もよくよく見ると、毎回要素bの1つしか更新していない。
更新式を分解してみると
min{a=0...N}(dp[i][a] + abs(a - X[i])) = min{ min{a=0...X[i]}(dp[i][a] - (a - X[i])), min{a=X[i]...N}(dp[i][a] + (a - X[i])) = min{ min{a=0...X[i]}(dp[i][a] - a) + X[i], min{a=X[i]...N}(dp[i][a] + a) - X[i] }
となり、dp[i][a] - aの区間最小値、dp[i][a] + aの区間最小値を聞く問題に帰着する。
よって、これを探して最小値を持ってくれば良い。
最後に -= abs(b-X[i]) するのに注意(他の要素は+abs(b-X[i])されているので、こちら側の遷移でされてない分引くことで帳尻が合う)
これでAC