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


実装リンク集 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で宣言します。

文字列の結合は`.`です。

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

```pl:0.pl
#!/usr/bin/perl
use strict;
my $a=<>;
my($b,$c)=glob<>;
print $a+$b+$c.$".<>
```

## 第１問 ABC086A Product

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

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

```pl:1.pl
#!/usr/bin/perl
<>=~$";print$`*$'%2?Odd:Even,$/
```

## 第２問 ABC081A Placing Marbles

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

boolを直接intとして扱うことができます。
また、未初期化の変数はundefですが、数値のコンテキストでは0として扱われます。

```pl:2.pl
$s=<>;
for(;$i<3;$i++){$r+=substr($s,$i,1) eq '1'}
print$r
```

## 第３問 ABC081B Shift only

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

arrの各要素に対し2で割ることが出来た回数の最小値です。
INF値として`1<<29`が使われていますが、2倍してオーバーフローしない中で簡潔に書ける数として競技プログラミングではよく使われます。

```pl:3.pl
#!/usr/bin/perl
$r=<><<29;
for(glob<>){
	$r0=0;
	for(;$_%2<1;$_=int($_/2)){$r0++}
	if($r>$r0){$r=$r0}
}
print$r
```

## 第４問 ABC087B Coins

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

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

```pl: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
```

## 第５問 ABC083B Some Sums

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

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

```pl: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
```

## 第６問 ABC088B Card Game for Two

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

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

```pl: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
```

## 第７問 ABC085B Kagami Mochi

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

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

```pl:7.pl
#!/usr/bin/perl
$n=<>;
$h{$_}=1 for<>;
print scalar keys %h;
```

## 第８問 ABC085C Otoshidama

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

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

```pl: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"
```

## 第９問 ABC049C Daydream

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

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

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

```pl: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通り示します。どちらを使っても通ります。

```pl: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'
```