AtCoderに登録したら解くべき精選過去問10問をD言語で解いてみた
精選過去問→AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~ - Qiita, Tasks - AtCoder Beginners Selection
いろんな言語のまとめ→百花繚乱!なないろ言語で競技プログラミングをする資料まとめ - Qiita
既にあるやつ
AtCoderに登録したら解くべき精選過去問10問をD言語で解いてみた (takeoさん)
AtCoderに登録したら解くべき精選過去問10問をD言語で解いてみた - D言語の構文と標準ライブラリを使い倒す編 - 矮小 (yousackさん)
(この記事の新規性は)ないです(たまにはブログ記事を書きたかった)
PracticeA - はじめてのあっとこーだー(Welcome to AtCoder)
import std.stdio : readf, readln, writeln; import std.string : strip; void main() { int a, b, c; string s; readf("%d\n", &a); readf("%d %d\n", &b, &c); s = readln.strip; writeln(a+b+c, " ", s); }
readf
でscanf
と同じように入力できます。ただし
- int以外も全部符号付き整数は
%d
, 符号なし整数は%u
で入力(%lld
とかはつかわない) \n
が無いと壊れる
などの違いがあります。
readln(1行読み込み)は最後に改行文字がくっついてくるのでstrip, chomp
などで取り除きましょう
なお,core.stdc.stdio
をimportするとC言語のscanf, printf
が使えるようになります。文字列の扱いが難しいのでおすすめしません
import core.stdc.stdio; import std.string : strip; void main() { int a, b, c; char[] s = new char[100]; scanf("%d %d %d %s", &a, &b, &c, s.ptr); printf("%d %s\n", a+b+c, s.ptr); }
ABC086A - Product
import std.stdio; void main() { int a, b; readf("%d %d\n", &a, &b); writeln(["Even", "Odd"][a*b%2]); }
配列リテラルは{1, 2, 3}
じゃなくて[1, 2, 3]
です
ABC081A - Placing Marbles
import std.stdio, std.string; import std.algorithm : count; void main() { string s = readln.strip; writeln(s.count('1')); }
s.count(x)
でx
の個数を数えられます
ABC081B - Shift only
import std.stdio; import std.algorithm : map, reduce, min; import std.string : split; import std.conv : to; void main() { readln; //ignore n int[] l = readln.split.to!(int[]); auto f(int x) { //xが何回2で割れるか返す int cnt = 0; while (x % 2 == 0) { cnt++; x /= 2; } return cnt; } writeln(l.map!f.reduce!min); }
高階関数ってやつをやってみます
l
: 入力した配列ですl.map!f
:l
の各要素にf
を適用した配列(のようなもの)です。たとえばl=[8, 12, 40]
ならl.map!f = [3, 2, 3]
l.map!f.reduce!min
:l.map!f
の各要素をmin
を使って畳み込みます,つまりl.map!f = [a, b, c, ...]
としてl.map!f.reduce!min = min(a,b,c,... )
ABC087B - Coins
import std.stdio; void main() { int a, b, c, x; readf("%d\n%d\n%d\n%d\n", &a, &b, &c, &x); int ans = 0; foreach (i; 0..a+1) foreach (j; 0..b+1) foreach (k; 0..c+1) { int y = i*500 + j*100 + k*50; if (y == x) ans++; } writeln(ans); }
foreach (i; a..b)
はfor (int i = a; i < b; i++)
とだいたい同じです
ABC083B - Some Sums
import std.stdio, std.string, std.conv, std.algorithm; import std.algorithm : sum; import std.range : iota; void main() { int n, a, b; readf("%d %d %d\n", &n, &a, &b); bool ok(int x) { string s = x.to!string; int t = s.map!"a-'0'".sum; return a <= t && t <= b; } writeln(iota(1, n+1).filter!ok.sum); }
iota(1, n+1)
:[1, 2, ..., n]
とだいたい同じです。python2でいうと前者がxrange
で後者がrange
です。filter!ok
: これも高階関数で,ok(x) = true
となるような要素だけ残します。sum
: sumを求めます(そうだね)。
つまり,[1, 2, ..., n]
からok
に入力するとtrue
になるようなものを列挙して,それの総和を求めるというコードです。
ABC088B - Card Game for Two
import std.stdio, std.string, std.conv; import std.algorithm : sort, each; import std.range : array; void main() { readln; //ignore n int[] a = readln.split.to!(int[]).sort!"a>b".array; int[2] res; //alice, bob a.each!((i, x) => res[i%2] += x); writeln(res[0] - res[1]); }
each
でループと同じようなことが出来ます。
ABC085B - Kagami Mochi
import std.stdio, std.range, std.algorithm; import std.algorithm : uniq; void main() { int n; readf("%d\n", &n); int[] a = new int[n]; foreach (i; 0..n) { readf("%d\n", &(a[i])); } writeln(a.sort.uniq.array.length); }
a.sort.uniq
でsortしてuniqueします。
ABC085C - Otoshidama
import std.stdio, std.range; import std.algorithm : cartesianProduct; void main() { int n, y; readf("%d %d\n", &n, &y); int ans = 0; foreach (p; cartesianProduct(iota(n+1), iota(n+1))) { int a = p[0], b = p[1], c = n-a-b; if (c < 0) continue; int x = a*10000 + b*5000 + c*1000; if (x == y) { writeln(a, " ", b, " ", c); return; } } writeln("-1 -1 -1"); }
公式ドキュメント読んでたらcartesianProduct
とかいうの見つけたので使います。
cartesianProduct([1, 2], [3, 4]) = [[1, 3], [1, 4], [2, 3], [2, 4]]
みたいな感じっぽいです。つまり二重ループが出来ます
ABC049C - 白昼夢 / Daydream
import std.stdio, std.string, std.regex; void main() { string s = readln.strip; auto r = regex(r"^(dream|dreamer|erase|eraser)*$"); if (s.matchFirst(r)) { writeln("YES"); } else { writeln("NO"); } }
ABC086C - Traveling
import std.stdio; import std.math : abs; import std.typecons : tuple; import std.meta : AliasSeq; bool solve() { int T; readf("%d\n", &T); int bt = 0, bx = 0, by = 0; foreach (i; 0..T) { int t, x, y; readf("%d %d %d\n", &t, &x, &y); int dt = t-bt; int di = abs(x-bx) + abs(y-by); if (di % 2 != dt % 2 || dt < di) { return false; } AliasSeq!(bt, bx, by) = tuple(t, x, y); } return true; } void main() { writeln(solve() ? "Yes" : "No"); }
AliasSeq!(a, b, c) = tuple(d, e, f)
でC++のtieと同じようなこと(複数同時代入)が出来るっぽいです。