Edited at

AtCoder に登録したら解くべき精選過去問 10 問を Perl で解いてみた

More than 1 year has passed since last update.

実装リンク集 https://qiita.com/drken/items/6edb1c0542d4c3b7179c

問題一覧 https://abs.contest.atcoder.jp/assignments

私の実装
記事

Ruby (私家版)
https://qiita.com/cielavenir/items/c0a45b6b87c411b60b93

Swift
https://qiita.com/cielavenir/items/b90a94dce60a620fa2dc

C
https://qiita.com/cielavenir/items/ee1e47b844d05dcfc66e

VB.Net
https://qiita.com/cielavenir/items/7ddf5e9bac02daf72159

Pascal
https://qiita.com/cielavenir/items/530270ac4affca435442

Perl
https://qiita.com/cielavenir/items/4d16ba1be4ad6847a914

MoonScript/Lua
https://qiita.com/cielavenir/items/6553531e230f39cd6a3d


入力

@a=split(/ /,<>);@a=split(' ',<>);は使いません。というわけでこの節だけ入門を逸脱します。ご容赦ください。てかこれを書きたくてPerlを担当したようなもの^^;


  • トークン1個 $n=<>;

  • トークン2個 <>=~$"; $` $'

  • トークン3個 <>=~/ (.+) /; $` $1 $'

  • トークン3個(数値) <>=~/ .+ /; $` $& $'

  • トークン4個(数値) <>=~/ .+ (.+) /; $` $& $1 $'

  • トークン2・3個ないし4個以上 @a=glob<>;

そういえばですが、AtCoderの入力例で<STDIN>と書かれていますが、<ARGV>としても差し支えありません。そして、<><ARGV>と同じ意味なのです。


解答


例題 PracticeA

https://practice.contest.atcoder.jp/tasks/practice_1

最初なので真面目にやります。use strictを付け、変数はmyで宣言します。

文字列の結合は.です。

あまり知られていませんが、節の最後の文は;を付けなくて良いです。


0.pl

#!/usr/bin/perl

use strict;
my $a=<>;
my($b,$c)=glob<>;
print $a+$b+$c.$".<>


第1問 ABC086A Product

https://abc086.contest.atcoder.jp/tasks/abc086_a

Perlでは文字列を引用符で囲わなくても通る場合があります。

あと、今回に限り改行文字($/)を律儀に出力しました(例題は入力した文字列をchompせずに出力しているので問題ありません)。AGC001以降の問題では実は出力は改行空白区切りのいずれでもよく終端改行も不要なので、以降は改行は出力しません。


1.pl

#!/usr/bin/perl

<>=~$";print$`*$'%2?Odd:Even,$/


第2問 ABC081A Placing Marbles

https://abc081.contest.atcoder.jp/tasks/abc081_a

boolを直接intとして扱うことができます。

また、未初期化の変数はundefですが、数値のコンテキストでは0として扱われます。


2.pl

$s=<>;

for(;$i<3;$i++){$r+=substr($s,$i,1) eq '1'}
print$r


第3問 ABC081B Shift only

https://abc081.contest.atcoder.jp/tasks/abc081_b

arrの各要素に対し2で割ることが出来た回数の最小値です。

INF値として1<<29が使われていますが、2倍してオーバーフローしない中で簡潔に書ける数として競技プログラミングではよく使われます。


3.pl

#!/usr/bin/perl

$r=<><<29;
for(glob<>){
$r0=0;
for(;$_%2<1;$_=int($_/2)){$r0++}
if($r>$r0){$r=$r0}
}
print$r


第4問 ABC087B Coins

https://abc087.contest.atcoder.jp/tasks/abc087_b

500円玉と100円玉の枚数を全探索します。


4.pl

#!/usr/bin/perl

($a,$b,$c,$x)=<>;
for($i=0;$i<=int($x/500);$i++){
for($j=0;$j<=int(($x-500*$i)/100);$j++){
$k=$x-500*$i-100*$j;
$r+=$k%50==0&&$c>=int($k/50)&&$a>=$i&&$b>=$j
}
}
print$r


第5問 ABC083B Some Sums

https://abc083.contest.atcoder.jp/tasks/abc083_b

変数sは各i(j)を10で割れるだけ割って、その間に出た余りの和です。


5.pl

#!/usr/bin/perl

<>=~/ .+ /;
for($i=1;$i<=$`;$i++){
$s=0;
$j=$i;
for(;$j;$j=int($j/10)){$s+=$j%10}
if($&<=$s&&$s<=$'){$r+=$i}
}
print$r


第6問 ABC088B Card Game for Two

https://abc088.contest.atcoder.jp/tasks/abc088_b

降順にソートしたら、符号を変えながら足しこんでいきます。


6.pl

#!/usr/bin/perl

$n=<>;
@a=sort {$b<=>$a} glob<>;
$t=1;
for($i=0;$i<$n;$i++){
$r+=$t*$a[$i];
$t=-$t
}
print$r


第7問 ABC085B Kagami Mochi

https://abc085.contest.atcoder.jp/tasks/abc085_b

$n=@aとすると、nに配列aの長さが代入されます。これを代入を経ずに得たい場合にscalarを使います。


7.pl

#!/usr/bin/perl

$n=<>;
$h{$_}=1 for<>;
print scalar keys %h;


第8問 ABC085C Otoshidama

https://abc085.contest.atcoder.jp/tasks/abc085_c

1000円札と5000円札の枚数を全探索します。


8.pl

#!/usr/bin/perl

<>=~$";
for($i=0;$i<=$`;$i++){
for($j=0;$j<=$`-$i;$j++){
$k=$`-$i-$j;
if($i*1000+$j*5000+$k*10000==$'){
printf("%d %d %d",$k,$j,$i);
exit
}
}
}
print"-1 -1 -1"


第9問 ABC049C Daydream

https://abc049.contest.atcoder.jp/tasks/arc065_a

文字列を逆にして比較していきます。

どうもscalarはscalarに変換するのではなく、その中身をscalar contextで評価せよっていう意味らしい?このコードのscalarは必須です。ないとlist contextになってしまうようです(正しくない)。


9.pl

#!/usr/bin/perl

@T=map {scalar reverse $_} ("dream","dreamer","erase","eraser");
$s=<>;
chomp($s);
$s=reverse($s);
$l=length($s);
for($c=0;$c<$l;){
$k=-1;
for($i=0;$i<4;$i++){
if(substr($s,$c,length($T[$i])) eq $T[$i]){
$k=length($T[$i]);
last;
}
}
if($k<0){
print'NO';
exit
}
$c+=$k;
}
print'YES'


第10問 ABC086C Traveling

https://abc086.contest.atcoder.jp/tasks/arc089_a

dx+dyがdt以下かつdtとの偶奇が一致。

2行目以降の入力は2通り示します。どちらを使っても通ります。


10.pl

#!/usr/bin/perl

for($n=<>;$n--;){
#@a=glob<>;$dt=$a[0]-$t;$dx=$a[1]-$x;$dy=$a[2]-$y;
<>=~/ (.+) /;$dt=$`-$t;$dx=$1-$x;$dy=$'-$y;
if($dx+$dy>$dt || ($dt-$dx-$dy)%2){
print'No';
exit
}
$t=$`;
$x=$1;
$y=$';
}
print'Yes'