LoginSignup
11
5

More than 3 years have passed since last update.

AtCoder Beginner ContestのB問題の最短コードを読む(021-040)

Last updated at Posted at 2018-12-14

はじめに

AtCoderで使用できる言語のバージョンアップ・追加が2020/06/18の夕方に行われました。(実際には、2020/05/13の夜から2020/05/14の昼にかけて一度アップデートされたあと、問題が発生したために巻き戻されていました。)
このアップデートによって、この記事で紹介しているコードの大半が更新されたため、以下の内容は現在のAtCoderにおけるコードゴルフ環境に比べて古いものになります。(定期的な記事の更新は諦めました。)

言語別索引

各問題の最短コードであるものにはByte数が書かれています。

Bash

ABC022 23Byte
ABC029 11Byte

Perl

ABC026 39Byte
ABC035 77Byte
ABC037 52Byte

ABC022
ABC024
ABC028
ABC031
ABC032
ABC038

Ruby

ABC023 45Byte

ABC022

Sed

ABC021 36Byte
ABC038 30Byte

Awk

ABC024 43Byte
ABC025 82Byte
ABC030 37Byte
ABC031 38Byte
ABC033 48Byte
ABC034 12Byte
ABC039 7Byte

ABC027
ABC038
ABC040

Octave

ABC024
ABC027
ABC036
ABC040

Perl6

ABC027 57Byte
ABC028 23Byte
ABC032 36Byte
ABC036 25Byte
ABC040 41Byte

ABC026
ABC034
ABC039

問題

ABC021 嘘つきの高橋くん

$N$
$a \quad b$
$K$
$P_1 \quad P_2 \quad ... \quad P_K$

$a,b,P_1,P_2,...,P_K$に重複する要素があればNOを、なければYESを出力します。

Sed(36Byte)
2h
4!d
G
/\<\(.*\) .*\<\1\>/cNO
cYES

コードを読む前に、sedの重要な機能「ホールドスペース」を知る必要があります。

ABC-Aでさんざん使ってきたように、sedは基本的に入力を1行ごとにパターンスペースに読み込み、コマンドを実行して加工されたパターンスペースの内容を出力することを繰り返す言語です。
これに対して「ホールドスペース」は、行をまたいで情報を保持する、パターンスペースの対になるものであり、1行ごとに自動的に内容が更新されたり、内容を出力されたりすることのないものです。

コマンドを使ってホールドスペースに文字列を保存することで、上書きされたり取り出されるまでは以降のどの行でも同じ文字列を得ることができます。

さて、それぞれのコマンドは以下のような意味になります。
h:パターンスペースの内容をホールドスペースに上書きする。
d:現在のパターンスペースの内容を全削除し、次の行の処理を始める。
G:ホールドスペースの内容をパターンスペースに追加する。

まず、2行目を処理するときのみhが実行されます。$P_1,P_2,...,P_K$と$a,b$に重複する要素がないか確認するため、$a,b$を一時的に保存しています。
次に、4行目「以外(!による効果です)」を処理しているときdが実行されます。これによって即座に次の行の処理が始まるため、以降のスクリプトは入力の4行目でのみ実行されます。
Gを実行すると、現在のパターンスペース$P_1,P_2,...,P_K$の後ろに改行と$a,b$が追加されます。

ここで、パターンスペースにまったく同じ単語が2つ存在すれば重複する要素が存在するとわかります。
これは、/\<\(\w*\)\>.*\<\1\>/という正規表現で判定できます。\<は単語の先頭の位置、\>は単語の末尾の位置にマッチします。
\(\w*\)\1の間に何文字存在しても良いように、間に.*を置いています。

/\<\(\w*\)\>.*\<\1\>/をさらに縮めます。
まず、\w.でも構いません。こうすると、\1'2 3'という2つ以上の単語の列になり得ますが、これが複数回文字列中に出現する場合も単語が重複していることに変わりありません。
次に、こちらはテストケースハックですが、最初の\>にしてもACできます。このとき、$P_K$は右に空白ではなく改行が存在するので\(.*\)にマッチできなくなってしまいますが、幸い、$P_K$と$a$(制約より$P_K \ne b$です)が重複しているテストケースは存在しないため影響しませんでした。

以上2つの更新を加えて、/\<\(.*\) .*\<\1\>/が得られました。これにマッチすればNOを出力します。

ABC022 Bumble Bee

$N$
$A_1$
$A_2$
$:$
$A_N$

$\{A_1,A_2,...,A_{i-1}\} \ni A_i$を満たすような$i$の個数を出力します。

Bash(23Byte)
read;awk a[\$0]++|wc -l

1行目をreadで読み捨てし、2行目以降をawkで処理します。
配列a$0でアクセスすると、以前に出現した要素のどれかと等しければ(つまり、$\{A_1,A_2,...,A_{i-1}\} \ni A_i$を満たしていれば)a[$0]はインクリメントされているため正の数となり、その行が出力されます。
後置インクリメントを使うことで更新のタイミングをずらし、判定と処理をまとめています。

こうして出力された行の数をwc -lでカウントすると、答えが得られます。

Perl(26Byte)
print<>-(grep!$$_++,<>),$/

AWKの解法と同じく出現回数をカウントするのですが、perlでは以前に出現したことのあるものではなく以前に出現したことの「ない」もの(つまり、リストのユニークな要素数です)を数え、$N$から引くことで答えを得ています。

1番目の<>はスカラ値が期待される文脈(「スカラコンテキスト」といいます)で評価されるので、1行読み込んだ値である$N$になります。
2番目の<>ですが、これはgrepという関数の第2引数であり、リストコンテキストなので、以降の入力すべてを読み込んで改行区切りにしたリストになります。

grepという関数はABC015-Bでも出てきました。第1引数で受け取った式やブロックに第2引数以降を次々と適用し、trueを返すもののみからなるリストを作ります。今回は、!$$_++という式を実行しています。こちらでも引数が自動的に$_に代入されます。
$$_についてはABC008-Bで出てきました。後置デクリメントでカウントするのはAWKと同じですが、!で真偽を反転しています。こうすることで、リストのユニークな値を抽出することができます。

grepを$N$から引くというスカラコンテキストで評価すると、返り値は得られたリストのサイズとなるので、これで答えが得られました。改行文字$/とともに出力します。

Ruby(27Byte)
p gets.to_i-([*$<]|[]).size

Perlと同じく、リストのユニークな要素数を数え$N$から引いています。
最初にgets.to_iで入力の1行目($N$)を読み込みます。

$<*splat展開し、展開されたものを[]でくくることで1つの配列にまとめています。これのユニークな要素を得るために、空の配列[]集合の和演算|)をしています。(実際には、sizeを呼び出すために括弧でくくる必要があり、uniqを呼び出すのと文字数は変わりません。)

$N$から[*$<]|[]sizeを引いたものが答えなので、pで出力します。

ABC023 手芸王

$N$
$S$

s1 ::= "b" | "b" <s3> "b"
s2 ::= "a" <s1> "c"
s3 ::= "c" <s2> "a"
としたときに、$S$がs1またはs2またはs3であれば$(N-1)/2$、そうでなければ$-1$を出力します。

Ruby(45Byte)
p~-`dd`[/.*
((?=ab|bc|ca).\g<1>.|b)$/].to_i/2

嘘解法です。まず下のRuby 53Byteの元最短コードを読んでください。

/(?=pat)/は肯定先読みで、続く2文字が/ab|bc|ca/にマッチすることを表します。\g<1>がどんどんコピーされ、文字列全体にマッチできたとき、/(?=ab|bc|ca)/によって文字列の前半分については連続する2文字がすべて/ab|bc|ca/のどれかであったことが言えます。
文字列の後ろ半分には何の制約もありませんが、これですべてのテストケースに正解することができました。

Ruby(53Byte)
p~-`dd`[/.*
(?!.*(?!ab|bc|ca)..)(.\g<1>.|b)$/].to_i/2

`dd`で入力をすべて読んでいます。
文字列のインデックスに正規表現を使用すると、マッチングに成功すればマッチした部分文字列、失敗した場合はnilが得られます。
今回は改行文字が含まれた正規表現を使用しています。正規表現中の改行文字は文字列中の改行文字にマッチングします。

まず、改行前の.*は、できるだけ長くマッチするという法則から、$N$の全体にマッチします。
次に改行の後ですが、実は$S$についての条件は「連続する2文字は必ず/ab|bc|ca/のどれかである」「文字列長は奇数で、中央の文字は'b'である」の2つで表すことができます。2つ目の条件により、中央から文字がどんどん決まっていくので、このような文字列は文字列長に応じてただ1つに定まります。

1つ目の条件は/(?!.*(?!ab|bc|ca)..)/で確認できます。/(?!pat)/は「否定先読み」と言って、/pat/が続かないような文字列中の位置にマッチします。詳しくは正規表現ページ内の「先読み、後読み(lookahead, lookbehind)」を参照してください。
よって/(?!ab|bc|ca)../は後ろに/ab|bc|ca/が続かない位置から2文字、つまり「/ab|bc|ca/にマッチしない2文字」にマッチします。これが存在すれば$S$は条件を満たしません。
そこで、このような2文字が存在しないという条件を表すため、さらに/(?!pat)/を使います。文字列中の何文字目に表れてもいいように/.*/を加え、/(?!.*(?!ab|bc|ca)..)/で「この先のいかなる2文字も/ab|bc|ca/にマッチしないことがない(つまりマッチする)」位置が表せました。
直前の改行が/^/の役割を果たしているので、これで入力の2行目において連続する2文字が必ず/ab|bc|ca/のどれかであることが言えました。

2つ目の条件は/(.\g<1>.|b)/で表せます。\g<1>は別の場所の正規表現をそのままコピーしてくるように働きます。
ここで、マッチした文字列ではなく、マッチする正規表現自体がコピーされることに注意してください。こちらも詳しくは正規表現ページ内の「部分式呼び出し(subexpression call)」を参照してください。
\g<1>によって、1番目の括弧内の正規表現である/.\g<1>.|b/がコピーされます。(/(?!.*(?!ab|bc|ca)..)/の括弧がカウントされていないことに注意してください。)
こうやってどんどん\g<1>がコピーされると同時に、先頭と末尾から1文字ずつ/./にマッチしていきます。文字列長が奇数であれば、最後に残るのは文字列の中央の文字であり、さらにそれが/b/にマッチすれば条件を満たします。文字列長が偶数であれば、最後に空文字列が残ってしまい、マッチングに失敗します。

マッチングに成功すると、入力全体が得られます。これをto_iすると、改行文字以降は無視され、$N$が得られます。~-aa-1を表し、2で割ると答えが得られます。
マッチングに失敗すると、nilが得られます。これをto_iすると0になり、~-0/2すなわち-1/2はRubyが切り捨ての割り算を行うため-1になります。
条件を満たす場合$N$は必ず奇数なので、切り捨てが行われるのにわざわざ~-をつけているのはマッチングに失敗したときのためだけです。

こうして場合分けをせずに答えが得られたため、pで出力します。

ABC024 自動ドア

$N \quad T$
$A_1$
$A_2$
$:$
$A_N$

$A_{N+1}=\infty$として、$\sum_{i=1}^N {\rm min}(A_{i+1}-A_i,T)$を出力します。

Awk(43Byte)
{a-=$1<s-T?s-$1:T;s=T?$1:T=-$2}END{print a}

実は、$A_0=-T$として$\sum_{i=0}^{N-1} {\rm min}(A_{i+1}-A_i,T)$も同じ値になります。
なぜなら$A_1 \ge 1$より${\rm min}(\infty-A_N,T)={\rm min}(A_1-(-T),T)=T$であるからです。
入力の1行目で$A_0$を計算できるため、$A_{N+1}$よりも$A_0$のほうが扱いやすいので、後者の式を用います。

まず、先にs=T?$1:T=-$2を読みます。
sは直前の$A$の値を覚えておく変数であり、変数Tが未定義であれば入力の1行目を処理していると判断して$-T$を代入します。そうでなければ$1を代入します。
ここで、-T=$2が文法的に正しくないので、T=-$2とする必要がありました。

a-=$1<s-T?s-$1:Tですが、$1<s-TT<s-$1と等しいため、s-$1Tのうち大きな方をaから引いています。
$-{\rm max}(A_i-A_{i+1},-T)={\rm min}(A_{i+1}-A_i,T)$より、示した計算式通りの値を足すことになります。

入力の1行目を処理している場合、$1>0s-T==0が成り立つので、a-=Tが実行されますが、T==0なのでaの値に余計なものが足されることはありません。

aが求める答えなので、ENDブロックで出力します。

Perl(48Byte)
<>=~$";$s+=$-=$_-$a,$a=$_+$' for<>;print$a-$s,$/

まずABC014-Bで用いたテクニックを使って$N$、$T$を読み込みます。

このコードでは、$A_0=-T$として$\sum_{i=0}^{N-1} {\rm min}(A_{i+1}-A_i,T)=\sum_{i=0}^{N-1} (A_{i+1}-A_i-{\rm max}(A_{i+1}-A_i-T,0))=A_N+T-\sum_{i=0}^{N-1} {\rm max}(A_{i+1}-(A_i+T),0)$を計算しています。

$aが$A_i+T$を保存するとすると、$A_0+T=0$なので、$aは初期化しなくてもよいです。
for<>$s+=$-=$_-$a,$a=$_+$'をループします。

まず$s+=$-=$_-$aですが、これは実は$sに${\rm max}(A_{i+1}-(A_i+T),0)$を足しています。
$-というのはPerlの組み込み変数で、代入された値は整数への切り捨てが行われ、負の数が代入されたときは0になるというとても便利な変数です。
つまり、$-=$aとするだけで0$amaxが得られるのです。

そのあと、$a=$_+$'$aの値を更新します。
$'forの間にはスペースが必要です。詳しくはPerl でコードゴルフをする時に空白が必要なのはどういう場合かを参照してください。

ループが終了した時点で、$aは$A_N+T$、$sは$\sum_{i=0}^{N-1} {\rm max}(A_{i+1}-(A_i+T),0)$となっているので、$a-$sを改行付きで出力します。

Octave(60Byte)
disp(int32(sum(min(t=(a=scanf("%d"))(2),diff(a(3:end))))+t))

$T+\sum_{i=1}^{N-1} {\rm min}(T,A_{i+1}-A_i)$を求めます。

scanf("%d")を使いフォーマット"%d"で入力をすべて読み、列ベクトルにして変数aに保存します。$T$はその2番目の要素なので、t=a(2)とします。
この操作を1度に行うとt=(a=scanf("%d"))(2)になります。

次に、$A_{i+1}-A_i$を求めます。これは隣接要素の差なので、diff関数が使えます。
変数aの3番目から最後までの要素が$A$を表すので、a(3:end)として取り出します。:は範囲を表し、endは行列のインデックス中で用いると最後の要素のインデックスになります。

こうして得られたtdiff(a(3:end))minを取り、sumで総和を計算します。min関数の引数は片方がスカラ、もう片方がベクトルですが、これは意図したとおりに動作します。

これまでの操作をまとめると、sum(min(t=(a=scanf("%d"))(2),diff(a(3:end))))になります。(関数の引数部分でtに代入しているため、余計な括弧が必要ありません。)

最後にtを足し、dispで出力するのですが、今回のジャッジでは先頭に空白があるとWAになってしまいます。それを避けるために、実数型で得られた答え("%d"で読み込んでいようと内部的には実数型です)をint32という関数で整数型に直しています。

ABC025 双子とスイカ割り

$N \quad A \quad B$
$s_1 \quad d_1$
$s_2 \quad d_2$
$:$
$s_N \quad d_N$

最初$0$にいて、$s_i$が'East'ならば東に、'West'ならば西に${\rm min}({\rm max}(d_i,A),B)$だけ移動します。
最後にいる場所を$East\quad X$または$West \quad X$または$0$と出力します。

Awk(82Byte)
d=A>$2?A:$2>B?B:$2{c+=/E/?d:-d}$3{A=$2;B=$3}END{print c?c<0?"West "e-c:"East "c:0}

まず、変数dに今回の移動距離を代入します。$A>d_i$ならば$A$、そうでなければ${\rm min}(d_i,B)$となります。
入力の1行目を処理しているときはABも未定義の変数なのでdの値は0になり、続くブロックが実行されません。

cに移動距離を加えていきます。/E/$0~/E/の省略形であり、入力中にEの文字があるかどうかを判定しています。
存在すれば$s_i$が'East'だとわかるのでc+=d、存在しなければc+=-dが実行されます。

$3が存在するときだけ、{A=$2;B=$3}というブロックが実行されます。$3が存在するのは入力の1行目だけなので、ここでABをそれぞれ入力の$A$と$B$で初期化しています。

最後にENDブロックで答えを出力しています。
c0であれば0を、c<0であれば"West "-cを文字列連結して、c>0であれば"East "cを文字列連結して出力します。
"West "-cは数値の引き算と解釈されてしまうので、"West "e-cという書き方になっています。ここでe0の代わりであり、未定義変数ならば何でもよいです。(0そのもので"West "0-cと書いてもよいです。)
今回は条件にc>0ではなくc<0を使っているので問題ないですが、printの後ろに>という記号が存在するとリダイレクトであると解釈されて文法エラーになることがあります。

ABC026 N重丸

$N$
$R_1$
$R_2$
$:$
$R_N$

$R$を昇順にソートし、$\pi \times ({R_N}^2-{R_{N-1}}^2+...+(-1)^i \times{R_{N-i}}^2+...+(-1)^{N-1} \times {R_1}^2)$を出力します。

Perl(39Byte)
<>;$\=$_*$_/.31831-$\for`sort -n`;print

ABC006-Bと同じく、$\に計算結果を保存することで出力を短縮しています。

上に示した式のように交互に符号を入れ替えつつ足し合わせる操作は、最初$now=0$として$now = {R_i}^2-now$を$i$の昇順に行うことで実現できます。

昇順ソートは、外部コマンドのsortを実行するのが1番短いです。1行目を読み飛ばしてあるので、sort -nは残りの$R$すべてを読み込み、数値として(これは-nオプションによります)昇順に並べて返します。
後置forで使われているので、sort -nを実行した結果はリストコンテキストで評価され、改行で区切られたリストになります。

よって、昇順に並べられた$R$がそれぞれ$_に代入されつつ$\=$_*$_/.31831-$\が実行されます。

出力を短縮したことにより出力部で$\pi$を掛けるのは不可能なので計算途中に掛けていますが、ここでも3.14159...をそのまま掛けるのではなく、その逆数0.31831...で割り算をしています。こうすることで、Perlにおいては先頭の0が省略できるので、1Byteの短縮になります。また、0.31831はこれ以上精度を落とすとWAになるというギリギリの数値になっています。

Perl6(41Byte)
say pi*reduce -*+* **2,sort !get,+<<lines

上と同じく$now = {R_i}^2-now$を行っています。reduceは、関数とリストを受け取ってHaskellなどで言うfoldを行います。

まず、reduceに渡しているリストであるsort !get,+<<linesを見ます。
1行目だけを先に読んで!で論理否定をし(Falseになります)、残りの入力をlinesで一気に読みこみます。これは入力を改行区切りでリストにして返す関数です。
この二つをひとまとめにsortするのですが、数値として比較したいため、+<<を使っています。(これについてはABC066-Aを参照してください。)
$now=0$とするために、わざわざ!getも一緒にsortしています。

reduceに渡している関数は、引数を2つとる必要があります。それが-*+* **2です。
これはWhateverCodeと呼ばれる機能で、*が演算子と一緒に現れた場合に関数が作られます。
* + *と書くと、これは2つ引数をとって和を返す関数になります。

-*+* **2は関数としては-> $x,$y {-$x+$y**2}と等しくなります。累乗の演算子**にも*が使われていますが、これは演算子であると正しく判定されます。

こうしてfoldすることで得られた値にpi($\pi$)を掛けて出力します。

ABC027 島と橋

$N$
$a_1 \quad a_2 \quad ... \quad a_N$

$\sum_{i=1}^N a_i \bmod N \ne 0$ならば$-1$を、そうでなければ$\sum_{j=1}^i a_j \ne i \times {\rm mean}(a)$であるような$i$の個数を出力します。

Perl6(57Byte)
say ($/=1/get*[+] $_=+<<get.words)%%1*-+^.grep($+=*-$/)-1

1/getは$1/N$であり、これに${\rm sum}(a)$を掛けることで${\rm mean}(a)$が得られます。
${\rm sum}(a)$は[+] $_=+<<get.wordsと書けます。ここで、$a$はもう1回使うのでリスト型に強制(ABC015-B参照)した後$_に保存しています。
こうして得られた平均値を$/に保存します。

$/が整数でなければ$\sum_{i=1}^N a_i \bmod N \ne 0$だとわかります。
$/%%1で「$/1で割り切れるかどうか」を表し、これがFalseであった場合(小数部分が存在するため$/は整数ではありません)、$/%%1*-+^.grep($+=*-$/)は全体として0になるため、say 0-1が実行されます。

$/%%1Trueであった場合は、say -+^.grep($+=*-$/)-1が実行されます。
.grep$_.grepの省略形です。$+=*-$/という関数を実行した結果がTrueのものを集めたリストを返します。
$\sum_{j=1}^i a_j \ne i \times {\rm mean}(a) \Leftrightarrow \sum_{j=1}^i (a_j-{\rm mean}(a)) \ne 0$ですから、$a$のそれぞれの値から平均値を引いたものを足し合わせつつ、0でないものを数えればよいです。

$+=*-$/は、ABC026で見たように、引数を1つとる関数になります。*-$/が$a_j-{\rm mean}(a)$に相当します。
累積和を保存する変数が$1文字になっていますが、これは明示的な宣言なしに使える無名の変数です。(variable $
コード中の出現する場所ごとに異なる変数として認識されますが(例えばsay $++,++$は「01」と出力する)、今回は関数の一部として使っているので、問題なく同じ変数として扱われます。
$に累積した和が0でなければ何もしなくともTrueになります。

-+^.grep($+=*-$/)-1ABC009-Aで見たように.grep($+=*-$/)+1-1と等しく、リストはスカラコンテキストではその大きさを表すので、無事答えが得られました。

Awk(65Byte)
z{for(;n<NF;)s+=$++n;for(;i<n;r+=c*n!=s*i)c+=$++i;$0=s%n?-1:r}z++

1行目を処理する際、先頭のzは未定義の変数なので、ブロックは実行されません。末尾のz++は後置インクリメントなので、出力も行われません。
対して、2行目を処理する際はすでにインクリメントされているので、ブロックも実行されるし出力も行われます。

ブロック内部を読みます。
まず、for(;n<NF;)s+=$++nで$a$の総和を求め、変数sに保存しています。
ここで、NFはフィールド数を表し、$++n$(++n)とパースされます。
nをインクリメントするタイミングを調整して、$1から$NFまでアクセスしています。

次に、for(;i<n;r+=c*n!=s*i)c+=$++iで$\sum_{j=1}^i a_j \ne i \times {\rm mean}(a)$を満たす$i$をカウントしています。
先のループを抜けた時点でn==NFが成り立っているので、こちらのループではNFの代わりにnを使用しています。
cに$a$をどんどん足しつつ、c*n!=s*iであればr1足しています。この式はc!=i*s/n、つまり上の条件の式と等しいです。

最後に、$0に答えを代入します。
s%n!=0であればs%ntrueとなり、-1が代入されます。s%n==0であれば前のループでカウントに使われた変数rが代入されます。
末尾のz++によって出力が行われます。

Octave(71Byte)
disp(int8((nnz(cumsum(a=center(dlmread(0)(2,:))))+1)*!any(mod(a,1))-1))

dlmread(0)(2,:)ABC015-Bと全く同じ使われ方をしています。

centerはベクトルの要素それぞれから平均値を引いたものを返す関数で、cumsumは累積和を計算する関数なので、これですべての$i$に対して$\sum_{j=1}^i(a_j-{\rm mean}(a))$が求まりました。
このうち値が0以外のものの個数を求めるのですが、ちょうどnnz関数があるので、これを使います。

さて、平均値が整数でない場合、center(dlmread(0)(2,:))の要素で整数でないものが存在します。
整数かどうかを確かめるのに、Octaveでも1で割ったあまりを使えます。
acenter(dlmread(0)(2,:))として、mod(a,1)でベクトルの要素それぞれの1で割ったあまりが一気に求まり、0でないものが存在するかはanyでわかります。これの真偽を反転すると、ちょうどPerl6のコードでいう$/%%1になるので、あとはPerl6と同じようにnnz(a)+1を掛けて1を引けば場合分けをせず$-1$の出力ができます。

そのままdisp関数で出力すると先頭の空白でWAになるので、int関数をかませるのですが、今回出力する値は-1から100の間です。このとき、int32という関数ではなくてint8という関数(8bit整数に変換する関数)を用いることで1Byte短縮することができます。

ABC028 文字数カウント

$S$

'A''B''C''D''E''F'が文字列$S$中にそれぞれ何回出現したかを空白区切りで出力します。

Perl6(23Byte)
get.ords.Bag{^6+65}.put

ordsは文字列を各文字の文字コードのリストにする関数です。
Bagは整数の重みがついた集合のようなもので、値ごとに何個存在するかをカウントして重みにします。
ordsから呼び出すことで、文字コードのリストから集合を構成します。
'A''B''C''D''E''F'はそれぞれ文字コードで656667686970なので、これら6つの要素の重みを空白区切りで出力すればよいです。
要素の重みを得るには、Bag{}でアクセスすればよいです。

文字コードは連続した値なので65..70と書くことができますが、さらに縮めて^6+65となります。
これは^6=0..5prefix ^)という範囲に65を加えていると読めて、範囲に数値を加えると始点と終点をシフトしたように動作します。(Shifting and scaling intervals)つまり、(0+65)..(5+65)=65..70です。

こうして、求める6つの値を配列として得ることができました。putという出力関数を使うと配列は空白区切りで出力されるので、フォーマットも正しく出力できます。

Perl(40Byte)
$s=<>;print"@{[map$s=~s/$_//g+0,A..F]}
"

$sに入力を読み込みます。
map$s=~s/$_//g+0,A..Fについてですが、まずA..Fは裸の単語であり'A'..'F'と書いたのと等しく、これはマジカルインクリメントと呼ばれる機能を用いて'A''B''C''D''E''F'と展開されます。
そのそれぞれに対して、$s=~s/$_//g+0が実行されます。$s$_'A''B'、……がそれぞれ入ります)にマッチする部分文字列がすべて(g)空文字列に置換され、置換に成功すれば置換した数が、失敗すれば空文字列が返されます。これを数値型に強制するために0を足しています。

こうして得られた値たちはmap関数によって配列にまとめられているので、それを空白区切りにして出力すればよいです。
配列@aを空白区切りの文字列に直したいときは、文字列展開を利用して"@a"と書きます。今回、mapの返り値は変数に代入されていませんが、このようなときも文字列展開を行う方法があります。それが@{[ ]}でくくるというものです。
まず配列を[]でくくることでリファレンス(参照)にし、次に@{}でくくることで配列のデリファレンスをします。

空白区切りの文字列を作った後、文字列の末尾で改行をするのですが、これは文字列に埋め込んだ方が短くなります。

ABC029 カキ

$S_1$
$S_2$
$:$
$S_{12}$

12個の文字列のうち文字'r'が含まれるものの個数を出力します。

Bash(11Byte)
grep r -c;:

bashのコマンドgrepは、テキスト中から正規表現にマッチする部分文字列が含まれる行を抜き出すものです。
grep r -cには引数が2つ渡されていて、このうちrが今回使用する正規表現です。意味はそのまま「文字'r'」です。
-cはオプションで、これはマッチした行ではなくその数を出力させるものです。つまり、このオプションを指定して実行すれば望む答えがいとも簡単に得られるということです。

ところが、grepの終了ステータス(C言語でいうreturn n;)は、1行もマッチしなかったときは1になります。つまり、grep r -cとだけ書くと、REになってしまうテストケースが存在するということです。
これを解消するために、セミコロンで区切ってコマンド:を実行しています。このコマンドは一切何もせずに正常終了する(終了ステータスが0である)だけのコマンドなので、これを最後に実行することでREを回避しています。

ABC030 時計盤

$n \quad m$

$d=((\frac{360}{12}n+\frac{360}{12 \times 60}m)-(\frac{360}{60}m))\bmod 360$として、${\rm min}(d,360-d)$を出力します。

Awk(37Byte)
180<$0=($1*60+$2)*5.5%360{$0=360-$0}1

${\rm min}(d,360-d)={\rm min}(360-d,360-(360-d))$なので$d$の代わりに$360-d$を求めることにします。
すると$360-d \equiv 360+5.5m-30n \equiv 5.5m+330n = (60n+m)\times 5.5 \pmod{360}$です。

$(60n+m)\times 5.5 \ge 0$なので、負の数の剰余などを気にせず$360$で割ったあまりを求められます。
そうして$0に代入しているのが、$0=($1*60+$2)*5.5%360の部分です。(AWKでは小数の剰余も正しく計算できます。)

$d>360-d \Leftrightarrow d>180$なので、$0>180が成り立つ場合は$0=360-$0を実行します。$0への代入文もまとめて書くと、条件の部分は180<$0=($1*60+$2)*5.5%360となり、これがtrueであればブロックが実行されます。

こうして$0に答えが代入されたため、1を評価して出力します。

ABC031 運動管理

$L \quad H$
$N$
$A_1$
$A_2$
$:$
$A_N$

すべての$i$について$\begin{cases}
L-A_i & (A_i<L) \\
0 & (L \le A_i \le H) \\
-1 & (H \lt A_i)
\end{cases}$ を各行に出力します。

Awk(38Byte)
$2{L=$1;H=$2}NR>2,$0=$1<L?L-$1:-($1>H)

$2trueであるのは2番目のフィールドが存在する入力の1行目だけなので、$2{L=$1;H=$2}で変数LHの初期化が行えます。

範囲パターンを使って、NR>2つまり3行目以降で出力が行われるようにしています。3行目以降であればNR>2は常に成り立つので、,の右辺の値にかかわらず毎回出力が行われます。

出力の内容ですが、まず$1<LであればL-$1となります。L<=$1のときに0または-1にしたいのですが、これはH<$10または1と評価されることを利用して、それの符号を反転させたものを出力します。$1<=Hであれば-0となりますが、これは0と区別されず、0と出力されます。H<$1であれば-1が出力されるので、これで正しく場合分け出来ています。

Perl(40Byte)
? ??<>:print$_<=$'?$-=$`-$_:-1,$/while<>

後置whileを使っています。通常、while文は変数$_に値を代入することはないのですが、唯一while<>という形で使ったときのみ、各行が$_に代入されます。
今回なぜ後置forを使っていないかというと、2行目の読み飛ばしをするためです。forはいったんすべての入力を読み込みますが、whileは毎回読み込みを行うのです。
whileでも入力をすべて読み込むまでループが回ります。

? ??<>:print$_<=$'?$-=$`-$_:-1,$/という式は三項演算子を用いており、(? ?) ? <> : print( ($_<=$'?$-=$`-$_:-1), $/)とパースされます。順に読んでいきます。

? ?というのは、特殊な正規表現の演算子です。正規表現のクォート風の演算子の「m?PATTERN?msixpodualngc」というところに説明がありますが、これは「1度だけしかマッチングを行わない」ということを除いて、通常のマッチングとまったく同じです。
暗黙的に$_とマッチングが行われるので、? ?は最初の1回(つまり、入力の1行目です)において$_=~/ /と等しく、$L$と$H$の間のスペースにマッチします。以降はマッチングを行うことなく偽となります。

? ?が真だった場合は、<>が実行されます。これは2行目の読み飛ばしを行います。(? ?を使っているので1度しか実行されません。)
<>はスカラコンテキストとリストコンテキストで読み込み方が異なります。このコードでは<>は読み込んだ値を全く使用しない場所に置かれています。これはvoid contextと呼ばれ、スカラコンテキストの1種なので、1行だけ読み捨てが行われます。

print$_<=$'?$-=$`-$_:-1,$/で出力を行います。
$A_i \le H$($_<=$')のとき${\rm max}(L-A_i,0)$を出力したいので、ABC024-Bで使用した$-を使い、$-=$`-$_とします。
$A_i \gt H$であれば-1を出力します。
print関数の引数には改行文字として$/も入れておきます。

これで望む出力が得られます。whileで読み込むことになるのは1行目と3行目以降で、3行目以降は毎回print関数が呼ばれます。

ABC032 高橋君とパスワード

$s$
$k$

$s$の、$k$文字の連続した部分文字列の種類を出力します。

Perl6(36Byte)
say +set ~<<(get~~m:ov/.**{$+=get}/)

get~~m:ov/.**{$+=get}/でマッチングを行っています。m:ovというのはマッチングのオプションとして:ovを指定する書き方です。
:ovというのは:overlapの略で、重なった文字列を個別にマッチングさせるオプションです。(Overlap
$k$文字の連続した部分文字列すべてを正規表現で見つけようとすると、互いに重ならないようなものしか得られませんが、:overlapを指定することですべて見つけることができます。

使用する正規表現は/.**{$+=get}/です。.で任意の1文字、**で「$n$回繰り返す」ことを表現できます。その$n$にあたる部分が{$+=get}で、ABC027-Bでも使った変数$getを足しています。
なぜわざわざ変数に足しているのかというと、この{}の内部にはPerl6コードを書けるのですが、それがマッチングのたびに評価されるからです。
最初の評価のときに$が$k$になり、以降は読み込みがEOFに達しているためgetNilしか返さず、Nilは数値としては0なので、$の値は変わらず$k$であり続けるというわけです。

こうして$k$文字の連続した部分文字列が取り出せました。
リストになっているのでそのユニークな要素数を求めたいのですが、実はマッチングによって得られる部分文字列はMatchというクラスに属しており、Set(集合)を作ったりuniqueを実行するときに値の同値性を調べる演算子===ではすべて同じものであると判定されてしまうのです。

そのため、いったん~<<でリストのすべての要素に文字列化の単項演算子~を前置し、文字列に直しています。こうすることで正しく同値性が判定されるようになったので、setを構成し、それを数値として評価することで重複しない要素の個数が得られました。

Perl(47Byte)
($_,$=)=<>;/.{$=}(??{$%+=!${$&}++})/;print$%,$/

まず入力部の($_,$=)=<>を読みます。この<>は代入先がリストになっているので、リストコンテキストで評価されます。よって、この1文で$_に$s$を、$=に$k$をそれぞれ代入できます。

次の/.{$=}(??{$%+=!${$&}++})/$_にマッチングを試みる正規表現です。
Perl6では:overlapというオプションを使って$k$文字の部分文字列すべてを取り出しました。Perlにはそんな便利な機能はありません。そこでテクニックとして、「マッチングを失敗させる」というものがあります。

正規表現として「任意の$k$文字」+「文字列中に現れないもの」を指定すると、当然マッチングは失敗します。しかし、その失敗に至るまでに、ありうるすべての$k$文字の部分文字列を取り出しているはずです。なぜなら、指定した正規表現のうち最後の「文字列中に現れないもの」を確かめるまでは、マッチングは成功しているからです。

よって、マッチングの途中でPerlコードを実行することができれば、取り出している途中の文字列を見ることによって、すべての$k$文字の部分文字列が得られます。
これは実は、Perl特有の正規表現の拡張パターンを使用して実現できます。

何をやりたいかが分かったところで、実際の正規表現を読みます。
.は任意の1文字を表し、{$=}は直前の要素の$=回の繰り返しを表します。ここで、$=は正規表現自体によって展開されるので、もし末尾に改行がついたままであるなら、
/.{k
}(??...

というふうに正しくない位置で改行しているとみなされてREになります。
今は$=を使っていますが、これは整数を保持する組み込み変数であり、値が代入された時点で数値として評価されるため、末尾の不要な文字(ここでは改行文字)が自動的に削除されます。この機能を使うために、$k$は$=に代入されました。

(??{$%+=!${$&}++})は、上の議論によれば「文字列中に現れないもの」のはずです。
(??{ code })というのがマッチングの途中でPerlコードを実行する方法であり、実際にマッチングする際に内部のブロックが評価され、その戻り値が正規表現として使用されます。
後で述べますが、今回の戻り値は必ず数値になるので、それで「文字列中に現れないもの」が指定できます。

codeの部分、$%+=!${$&}++を読みます。
まず、$&というのは正規表現にマッチングした部分の文字列を表します。ここではまだマッチングは終了していませんが、取り出している途中の文字列が入っているので、これを使うことで$k$文字の部分文字列が得られます。
${$&}には、ABC008-Bと同じテクニックを使っています。$%+=!${$&}++によって、ある文字列の最初の出現でのみカウント変数$%1足されるようになります。(文法エラーが起こるため$$&とは書けません。)
戻り値は加算が行われた後の$%なので、先に言ったように必ず数値になります。

このマッチングが無事終了すれば、$%には答えが入っているので、改行文字とともに出力を行います。

$k$が文字列$s$の長さより大きい場合は、そもそも(??{ code })が1回も実行されず、カウント変数が未定義値のままになってしまい、0ではなく空文字列を出力してしまいます。そのWAを防ぐために、$=と同じく整数を保持する組み込み変数$%がカウント変数に選ばれています。($=は初期値が60なので、この用途には向きません。)

ところで、$$&とは書けず、${$&}と書いていると述べました。実はAtCoderのPerl (v5.18.2)のインタプリタは不思議な挙動をし、
$
$&

と間に改行を入れることで${$&}と同じ意味になります。新しいバージョンではこういう挙動をしなくなっています。
今回は改行を入れると文法エラーを起こすため使用できませんでした。

ABC033 町の合併

$N$
$S_1 \quad P_1$
$S_2 \quad P_2$
$:$
$S_N \quad P_N$

$2P_i \gt \sum_{j=1}^N P_j$が成り立つような$i$が存在すれば$S_i$、しなければatcoderと出力します。

Awk(48Byte)
a+p<a+=$2{s=$1;p=$2}END{print a<p*2?s:"atcoder"}

条件を満たすような$i$が存在するとき、明らかに$P_i$は$P$の最大値なので、その最大値を求めます。

a+p<a+=$2ですが、これの両辺からaを引くとp<$2になり、これまでの$P$の最大値pと今見ている$2の値を比較しています。
変数aに$P$の総和を計算するのを同時に行うために、こういう書き方になっています。

p<$2であれば、ブロックの中でpの値を更新するとともにそのときの$S$をsに保存しています。
1行目を処理しているとき、$2は数値としては0なので、$P$の総和を計算することに影響を与えませんし、ブロックも実行されません。

ENDブロックで出力を行います。a<p*2が成り立てばsに保存されている$S_i$を、成り立たなければ"atcoder"を出力します。

ABC034 ペア

$n$

$ \begin{cases}
n+1 & \text{if $n$ is odd} \\
n-1 & \text{if $n$ is even}
\end{cases}$を出力します。

Awk(12Byte)
$0-=1-$0%2*2

$n \bmod 2$を使って場合分けをなくすことを考えます。
$n \bmod 2$が$1$ならば$1$を、$0$ならば$-1$を$n$に足せばよいですが、これは$(n \bmod 2)\times 2-1$で得られます。
上に示したコードでは、$0%2*2-1を足す代わりに1-$0%2*2を引いています。

Perl6(14Byte)
say get+1+^1-1

Perl6では++^bitwise XOR)の優先順位が同じなので、上のコードは((get+1)+^1)-1と解釈されます。
場合分けをして読みます。

  • $n$が偶数のとき)get+1は奇数であり、(get+1)+^1で下1ビットが0に戻るためgetに等しく、最終的にget-1となる。
  • $n$が奇数のとき)get+1は偶数であり、(get+1)+^1は下1ビットが1にセットされてget+2となるため、最終的にget+1となる。

よって偶奇どちらも正しい答えが得られていることがわかりました。

ABC035 ドローン

$S$
$T$

文字列$S$中の文字$a$の個数を$C_a$として、$\begin{cases}
|C_L-C_R|+|C_U-C_D|+C_? & (T=1)\\
|C_L-C_R|+|C_U-C_D|-C_? & (T=2 \land |C_L-C_R|+|C_U-C_D| \ge C_?)\\
(|C_L-C_R|+|C_U-C_D|-C_?)\bmod 2 & (T=2 \land |C_L-C_R|+|C_U-C_D| \lt C_?)
\end{cases}$を出力します。

Perl(77Byte)
$_=<>;$d=abs(y/R//-y/L//)+y/?//*(3-<>*2)+abs y/U//-y/D//;print$d<0?$d%2:$d,$/

入力を$_に読み込み、ABC003-Bで用いたのと同じ方法で、y///を利用して文字数を数えています。

3-<>*2では$T$を読み込んでいて、$T=1$のときは1を、$T=2$のときは-1y/?//に掛けています。これは、上で示した場合分けで$C_?$の係数が$T$の値によって異なることを反映しています。

また、abs(y/R//-y/L//)abs(y/U//-y/D//)の片方を式の1番後ろに持ってくることによって、関数呼び出しの括弧を省いています。

$T=1$のとき$|C_L-C_R|+|C_U-C_D|+C_?$、$T=2$のとき$|C_L-C_R|+|C_U-C_D|-C_?$が得られ、$dに代入しています。上の場合分けですが、$T=1$のときの$|C_L-C_R|+|C_U-C_D|+C_?$は明らかに0なので、結局$dの値が0以上ならばそのまま、0未満ならば2で割った余りが答えであるとわかります。

よって、$d<0?$d%2:$dと改行を出力すればよいです。

ABC036 回転

$N$
$s_{1,1} \quad ... \quad s_{1,N}$
$:$
$s_{N,1} \quad ... \quad s_{N,N}$

マス目を時計回りに90度回転させて出力します。

Perl6(25Byte)
put [RZ~] get.comb xx get

xxはリストを作成する演算子です。先に右の項getが評価され、左項get.combは繰り返すたびに評価されるので、get.comb xx getは$N$回入力を読み込んでそれぞれ文字のリストに分解した「リストのリスト」になります。

[RZ~]はリストをRZ~という演算子でfoldする書き方です。このRZ~という演算子はややこしくて、まず~という文字列連結の演算子があり、それを「リストを2つ受け取って要素ごとに演算する」ようにするメタ演算子Zで修飾し、最後に「左項と右項を入れ替える」ようにするメタ演算子Rで修飾したものです。

例示をします。
'a' ~ 'b''ab'になります。
( 'a', 'b' ) Z~ ( '1', '2' )( 'a1', 'b2' )になります。
( 'a', 'b' ) RZ~ ( '1', '2' )( '1a', '2b' )になります。

foldすると以下のようになります。
[ RZ~ ] ( ( 'a', 'b', 'c' ), ( 'd', 'e', 'f' ), ( 'g', 'h', 'i' ) )
-> ( 'a', 'b', 'c' ) RZ~ ( 'd', 'e', 'f' ) RZ~ ( 'g', 'h', 'i' )
-> ( 'a', 'b', 'c' ) RZ~ ( 'gd', 'he', 'if' )
-> ( 'gda', 'heb', 'ifc' )

これは、左の入力が右の状態になったのと同じであり、90度回転されています。
abc -> gda
def -> heb
ghi -> ifc
[Z~]によってもともと$s_{i,1} \quad ... \quad s_{i,N}$(横方向)と繋がっていた文字列を$s_{1,i} \quad ... \quad s_{N,i}$(縦方向)に繋ぎ変えており、その繋ぎ変える順番をRで逆転させたことにより、90度回転が実現されています。

最後に得たリストの要素を出力するのですが、この問題のジャッジでは改行区切りの代わりに空白区切りにしてもACすることができます。ABC028-Bでも使ったputという出力関数を使えば、デフォルトで空白区切りになって出力されます。

Octave(39Byte)
disp(rot90(scanf("%s",[input(0),99]))')

まず最初に1番内側のinput(0)が実行されます。これは入力を1行読み込み、それをOctaveの式として評価します。引数には入力を受け付ける際に出力するプロンプトを指定するのですが、ここに0を書くとアスキーコードで0つまりNULL文字が指定されたと見なされ、余計な出力がされなくなります。

次にscanf("%s",[input(0),99])が実行されます。scanf関数は、第1引数に与えられたフォーマット文字列に従って読み込めるだけ入力を読み込むのですが、第2引数に数値または数値のベクトルを指定すると、必要な分だけ読み込んでその次元の行列に成形してくれます。

フォーマット文字列の"%s"は空白に類しない1文字を表します。サイズは$N$行$99$列行列を指定しているのですが、入力にはそんなに文字がないので、途中で読み込みが打ち切られて$N$行$N$列の行列が返ります。

左の入力は右のように読み込まれます。
abc -> adg
def -> beh
ghi -> cfi
何が起こっているかというと、scanf関数はデフォルトでは列ベクトル(縦のベクトル)を返すので、その方向に優先的に詰めているのです。まず$N$文字読み込んで$1$列目に詰め、次に$N$文字読み込んで$2$列目に詰め……$99$列目に詰める前に入力が尽きるので$N$行$N$列の行列が返るのであり、もしも[input(0),99]ではなく[99,input(0)]と指定していたら$99$行の崩れた行列が返ります。
また、文字の行ベクトルは文字列と等価なので、行ごとに連結されているように見えます。

さて、出力は行単位なのであとは行ごとに文字列を反転すればよいのですが、上のコードでは(文字数は変わりませんが)別の方法を使っています。それがrot90( )'であり、まずrot90で反時計回りに90度回転させた後'で行列を転置しています。

先ほどの入力の例を使ってどうなるか確認します。順にscanfで読んだ状態、rot90、転置です。
adg -> ghi -> gda
beh -> def -> heb
cfi -> abc -> ifc

これでも行ごとに反転できることが確かめられました。disp関数は文字列を出力する際に余計な空白をつけず、また行列は行ごとに改行されるので、正しい出力が行われます。

ABC037 編集

$N \quad Q$
$L_1 \quad R_1 \quad T_1$
$:$
$L_Q \quad R_Q \quad T_Q$

最初、大きさが$N$ですべての要素が$0$の数列があります。これの$L_i$番目から$R_i$番目(1-indexed)を$T_i$に書き換える操作を$Q$回行ったあとの数列を、改行区切りで出力します。

Perl(52Byte)
@_=(0)x<>;@_[$`-/ .* /..$&-1]=($')x99for<>;print"@_"

改行区切りでと書きましたが、改行区切りである必要はありません。

入力の1行目をそのまま数値として評価すると、最初の空白以降の$Q$が無視されて$N$になるので、(0)x<>で$N$個の0を表せます。これを@_に代入します。

残りの入力をfor<>でループします。各ループごとに@_[$`-/ .* /..$&-1]=($')x99が評価されます。

$`-/ .* /..$&-1ですが、これはABC018-B$`-/ /..$'-1と同じテクニックを使っています。
正規表現/ .* /は「空白」+「任意の文字列」+「空白」にマッチします。入力の各行には空白が2つずつしかないので、「任意の文字列」の部分には空白に挟まれた$R_i$が当てはまります。
したがって、/ .* /を実行するだけで$`には$L_i$が、$&には$R_i$が、$'には$T_i$がそれぞれ代入されます。($&の先頭と末尾に空白文字も入っていますが、これは数値として扱う際は読み飛ばされるので問題になりません。)
1-indexed0-indexedに直す方法はABC018-Bと変わっていません。

こうしてアクセスした@_のスライスに、それぞれ$'を代入します。代入演算子の左項はリストなので、右項はリストコンテキストで評価されます。
そのまま$'を代入すると、大きさ1のリストを代入しているとみなされ、スライスの残りの部分が未定義値になってしまいます。これを防ぐために$'を$R_i-L_i+1$個用意するのですが、実はスライスに代入するリストがスライスより大きいと、余剰分は無視されます。つまり、わざわざ($')x($&-$`+1)とぴったり用意する必要はなく、十分に大きければ何でもよいのです。

制約より$R_i-L_i+1 \le 100$です。$<はAtCoderにおいて常に1000を表すので、これを使えば十分です。(テストケースハックをすると99で十分である($R_i-L_i+1 = 100$であるテストケースが存在しない)ことがわかるので、1Byte縮みます。また、数字とforの間は99forと空白を開けずに書いてもパースができます。)

こうしてすべての処理を行ったあとの@_を出力します。"@_"と書くと、リストの要素が空白区切りになるので、これでACできます。
実をいうと、リストに代入した$'には元の文字列の末尾の改行がくっついたままになっているので、実際の出力は改行と空白が一緒になってしまい、けっこう崩れています。それでも要素同士がくっついてしまうことはないので、ジャッジに正しく読み取ってもらえ、ACできました。

ABC038 ディスプレイ

$H_1 \quad W_1$
$H_2 \quad W_2$

$H_1 = H_2 \lor H_1 = W_2 \lor W_1 = H_2 \lor W_1 = W_2$ならばYES、そうでなければNOを出力します。

Sed(30Byte)
N
/\<\(.*\)\>.*\n.*\1/cYES
cNO

シンタックスハイライトが壊れていますが、Nは「パターンスペースに改行と次の行を追加する」コマンドです。

上の条件は、単純に言えば改行を挟んで同じ単語が2つ存在すればYESであるというものです。
それを/\<\(.*\)\>.*\n.*\1/で判定していますが、この正規表現はほとんどABC021-Bで使用したものと同じです。

\<\(\w*\)\>で単語をキャプチャし、\1との間に.*\n.*を指定して改行(\n)を挟んでいることを表しています。改行とそれぞれの単語の間に何文字あってもいいように.*を書いています。
そして、\w.にしてもいい理由もABC021-Bと変わりません。

入力は2行しかなく、最初にNを使い1行追加で読み込んでいるので、このスクリプトが実行されるのは1度きりとなります。当然出力も1回だけです。

Perl(31Byte)
<>=~$";print<>=~/$`|$'/x?YES:NO

<>=~$"で入力の1行目を$`$'に代入します。

入力の2行目が$`または$'にマッチすればYESです。正規表現としては/$`|$'/で表せます。……とはならず、$'の末尾に改行がついたままなので、それも含めてマッチする必要が出てきてしまい、正しくありません。正規表現にオプションxをつけると、改行を無視してくれるようになるので、これで正しく判定ができるようになりました。(/xについて

2行目の<>にマッチングすれば'YES'、しなければ'NO'を出力します。裸の単語機能を使ってクオートする手間を省いています。

Awk(32Byte)
s?$0=s~$1"|"$2?"YES":"NO":0>s=$0

三項演算子を使って、入力の1行目と2行目で処理を変えています。

1行目の時点では変数sは未定義なので、0>s=$0が実行されます。s$0を代入していますが、うっかり$0が出力されないよう0>$0という必ずfalseの式を評価するようにしています。

2行目では$0=s~$1"|"$2?"YES":"NO"が実行されます。
~はマッチングの演算子なので、s(入力の1行目)が$1"|"$2にマッチするかを確かめています。これは1行目と2行目が逆転した以外はPerlと同じ方法をとっています。
正規表現中で変数を展開できないので、文字列として正規表現を構成します。といっても$1"|"$2をこの順で連結するだけです。|は他の言語の正規表現と同じく「または」という意味です。

これにマッチングすれば"YES"を、しなければ"NO"を出力する、というのもPerlと一緒です。

ABC039 エージェント高橋君

$X$

$\sqrt[4]X$を出力します。この値は整数であることが保証されています。

Awk(7Byte)
$0^=.25

$1/4$、つまり$0.25$乗すればよいです。0.25の先頭の0は省けます(.251/4でByte数は変わりませんが)。
$0の値は必ず1以上になるので出力は行われます。

Perl6(11Byte)
say get**¼

このコードの面白い点は¼、この1文字がすべてです。

Unicodeで数字として登録されている文字は、Perl6において数値リテラルとして使用できます。
.251/4も3Byteですが、¼は2Byteです。

ABC040 □□□□□

$n$

$| n - \lfloor n/i \rfloor|+(n \bmod i) \quad (1 \le i \le n)$の最小値を出力します。

Perl6(41Byte)
say min $!/++$/+|0-$/+$!%$/xx sqrt $!=get

$n \le 10^5$なので、Perl6では$n$回ループするとTLEしてしまいます。実は$1 \le i \le \sqrt n$の範囲だけ試せばよいので、上のコードではそうしています。

コードをパースするとsay( min( ($!/++$/+|0-$/+$!%$/) xx sqrt($!=get) ) )となります。まず$!に入力を読み込み、それのsqrt$!/++$/+|0-$/+$!%$/を実行します。そうすると、各実行ごとの$!/++$/+|0-$/+$!%$/の値がリストになって得られるので、最小値を求めて出力しています。

では$!/++$/+|0-$/+$!%$/は何をやっているのでしょうか。
これもパースすると、(($! / ++$/) +| 0) - $/ + ($! % $/)になります。
ループを回すたびに$/をインクリメントすることで$i$の代わりに$/を使っています。

$!には$n$が入っているので、$! / ++$/$/をインクリメントしつつ$n/i$を求めています。これを0bitwise OR+|)することで、整数に切り捨てています。つまり(($! / ++$/) +| 0)で$\lfloor n/i \rfloor$となります。

$1 \le i \le \sqrt n$ならば$| n - \lfloor n/i \rfloor|=\lfloor n/i \rfloor-n$なので、(($! / ++$/) +| 0)から$/を引いています。
最後に、$! % $/($n \bmod i$)を足して、各$i$に対する$| n - \lfloor n/i \rfloor|+(n \bmod i)$が求められました。

それらの最小値が答えなので、先に述べたように求めて出力しています。

Awk(46Byte)
{for(m=$1;i++<j=int(m/i);$1>j&&$1=j)j+=m%i-i}1

変数mには最初$1、つまり$n$が代入されます。

i++<j=int(m/i)で$1 \le i \le \sqrt n$のループを行っています。
本来はi1に初期化してi<=int(m/i)とするところですが、i-1<int(m/i)と読み替えることでインクリメントをまとめることができ、初期化も必要なくなります。

$| n - \lfloor n/i \rfloor|+(n \bmod i)$を求めるためにj=int(m/i)-i+m%iとするのですが、このうちint(m/i)はループ条件式のところで出現しているので先に代入しておき、後からm%i-iを足しています。

$1を最小値を持っておく変数としており($0ではなく$1である理由はありません)、$1>j&&$1=jという式は$1>jであれば$1=jを実行します。この短絡評価を利用した書き方は三項演算子より短くなっています。

最後に1を評価して出力するのですが、答えは$0ではなく$1に入っています。
フィールド変数が個別に書き換えられた場合、AWKはフィールド変数を順番に並べ、変数OFS(デフォルトは" ")で連結して$0とします。(フィールドの内容を変更する参照)
今回はフィールドが1つしかないので、$2$3の部分に余計なものがなく、正しい出力が得られました。

Octave(49Byte)
disp(min(mod(n=input(0),a=1:n)+abs(a-fix(n./a))))

n=input(0)で入力を読み、nに代入しています。1:n1からnまでの1刻みの行ベクトルを表します。

mod(n,1:n)で、n1からnまでのそれぞれで割ったあまりが1度に得られます。
./は「要素ごと」の除算を表すので、n./(1:n)でこれまたn1からnまでのそれぞれで割った商が得られます。
fixは実数を0に向かって丸める関数で、0以上の数に対してはfloor関数と同じ役割を果たす2Byte短い関数として使えます。
fixabsもベクトルを与えられると要素ごとに計算します。
(1:n)-fix(n./(1:n))は要素ごとの引き算をするので、例えば最初の要素は1-fix(n/1)を表し、2番目の要素は2-fix(n/2)を表す……というふうに計算されます。

結局、mod(n=input(0),a=1:n)+abs(a-fix(n./a))というのは$(n \bmod i)+| n - \lfloor n/i \rfloor|$をすべての$1 \le i \le n$に対して一斉に計算している式です。こうしてループを回さずに並列的に計算できるのが、Octaveの強みです。

そうして得られたベクトルの最小値を求めて出力すればよいです。

11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5