AtCoder Beginner Contest 103の解説
A - Task Scheduling Problem
入力:
出力: i番目のタスク -> j番目のタスク でかかるコスト の最小値
というのは、数直線上に表すと2点間の距離と言い換えることができます。したがって、の最大値から最小値を引くことでこの問題を解くことができます。
(A => A.reduce!max - A.reduce!min)(readln.split.to!(int[])).writeln;
感想: A問題なのに問題文が難しかった。でも実装はA問題レベルだったなあ。
B - String Rotation
入力:
は英小文字からなる
出力: 操作(文字列の末端を先頭に持ってくる)を任意の回数繰り返してSをTに一致させられるなら'Yes'、そうでなければ'No'
素直に操作を繰り返せばいいです。(なので回操作を繰り返して一致するタイミングがあればYes)
auto S = readln.chomp, T = readln.chomp; foreach(i; 0..S.length) { string tmp = S[1..$]; tmp ~= S[0]; if(S == T) { writeln("Yes"); return; } S = tmp; } writeln("No");
上は素直に操作を繰り返す方法ですが、S同士を連結してSSという文字列(例: S="aba"のとき、SS="abaaba")を作り出し、その中にTが含まれるかを判定することでも解くことができます。
auto S = readln.chomp, T = readln.chomp; S ~= S; if(S.canFind(T)) writeln("Yes"); else writeln("No");
感想: SとTをsortしてS=TならYesでええやろ!wとか思ってたら全然違いました。ちゃんと考えることが大事。
C - Modulo Summation
入力:
出力: に対して、としたときのの最大値
入力例1を見てみると、がの最大値となっています。よく見てみると、それぞれの項で最大の値をとっていることがわかります。
では、ここでのはどういう意味を持つのでしょうか。問題ではとなっていますが、試しにの場合を考えてみましょう。そうすると…
となるのがわかります。ここで、このという値を正の整数で表せないか、と考えると、実はで表せるとわかります。実際、です。というわけで、求めるべき値は最終的にとわかります。以下で最大の5つの素数 をかけ合わせると という莫大な値をとり、これはぐらいです。unsigned long long(Dではulong)でも値を保持し続けることはBigIntを用いないと無理です。
auto N = ri; auto a = readln.split.to!(int[]); a.map!(b => b-1).sum.writeln;
実は、BigIntを使ってゴリ押しすることもできます。実際にmの値を計算してみる。
readln; auto a = readln.split.to!(BigInt[]); BigInt m = a.reduce!"a*b"-1; ulong tmp; foreach(i; a) { tmp += (m % i).to!ulong; } tmp.writeln;
ここでとしています。でもどちらでもOKです。
制約上、入力される正整数は3000個まで許容されており、fの最大値をとるmの最小値は14748桁になるようです。
(すべて互いに素だと仮定した場合、上のmの値2つは等しくなりますから、この主張は正しい…はず)
感想: ゴリ押しでも解けることがわかり、現代のコンピュータの性能はやっぱりヤバイなあと思った。
D - Islands War
入力:
制約は:
出力: 取り除く必要のある橋の本数の最小値
これは蟻本に乗っている区間スケジューリング問題に似ています。
橋を取り除くにあたり、最も少ない本数で済むようにするには、できるだけ東から切っていけばよいです。
となるようにソートして、foreachし、もし今までに切った地点より東側で「戦いの西側の国」が存在したら、「その戦いの東側の国の手前」で橋を切り落とす。これでACできます。
alias Task = Tuple!(int, "start", int, "end"); void main() { auto ip = readAs!(int[]), N = ip[0], M = ip[1]; Task[] tasks = new Task[](M); foreach(i; 0..M) { auto s = readAs!(int[]); tasks[i] = Task(s[0], s[1]); } tasks.sort!"a.end < b.end"; int d = 0; int res; foreach(t; tasks) { if(d <= t.start) { d = t.end; res++; } } res.writeln; }
感想: コンテスト中は「imos法とかUnionFindでいけそう」とか思ってて、解けませんでした。簡単めなD問題なので解きたかった。
A: Submission #2876592 - AtCoder Beginner Contest 103
B: Submission #2878868 - AtCoder Beginner Contest 103
B(連結方式): Submission #2890012 - AtCoder Beginner Contest 103
C: Submission #2877869 - AtCoder Beginner Contest 103
C(BigInt): Submission #2890307 - AtCoder Beginner Contest 103
D: Submission #2890508 - AtCoder Beginner Contest 103