はじめに
AtCoder:競技プログラミングコンテストを開催する国内最大のサイト では、言語のアップデートを予定しております。
アップデートにて、Perlの標準モジュールList::Util が増強されたりしますので、今のうちに習得しライバルとの差を縮めに差を付けましょう。
AtCoder で使用できるList::Util
配列やリストの操作に関する機能が追加されます。
Perl (v5.18.2) | Perl(v5.26.1) | |
---|---|---|
reduce | 〇 | 〇 |
any | × | 〇 |
all | × | 〇 |
none | × | 〇 |
notall | × | 〇 |
first | 〇 | 〇 |
max | 〇 | 〇 |
maxstr | 〇 | 〇 |
min | 〇 | 〇 |
minstr | 〇 | 〇 |
product | × | 〇 |
sum | 〇 | 〇 |
sum0 | 〇 | 〇 |
pairs | × | 〇 |
unpairs | × | 〇 |
pairkeys | × | 〇 |
pairvalues | × | 〇 |
pairfirst | × | 〇 |
pairgrep | × | 〇 |
pairmap | × | 〇 |
shuffle | 〇 | 〇 |
uniq | × | 〇 |
uniqnum | × | 〇 |
uniqstr | × | 〇 |
product
use List::Util qw(product);
print product 1..6; # => 6! = 720
print product (2, 2, 2, 2, 3, 3, 5); # => 720
階乗です 総乗でした
use List::Util qw(reduce);
print reduce {$a * $b} 1..6; # => 6! = 720
print reduce {$a * $b} (2, 2, 2, 2, 3, 3, 5); # => 720
reduce でも同じ計算が可能です
pairs
1次元配列を2つの要素で利用します。
AtCoder Beginner Contest 151 C - Welcome to AtCoder
use strict;
use warnings;
use 5.26.1;
use List::Util qw(pairs pairgrep pairkeys pairvalues uniq sum0);
my ($n, $m);
{
my $in = <STDIN>;
($n, $m) = split(" ", $in);
}
my @p;
for (my $i=0; $i<$m; $i++) {
@p = (@p, split " ", <STDIN>);
}
my @c = uniq pairkeys pairgrep {$b eq 'AC'} @p;
my (%d, %e);
for my $i (@c) {
$d{$i} = 1;
$e{$i} = 0;
}
for my $pair (pairs @p) {
if ($pair->value eq 'WA') {
if ($d{$pair->key}) {
$e{$pair->key}++;
}
} else {
$d{$pair->key} = 0;
}
}
say scalar @c, " ", sum0 pairvalues %e;
例えば、@p = (1, WA, 1, AC, 2, WA, 2, AC, 2, WA); と何の変哲もない配列ですが、pairs @p としますと次のように扱うことができます。
pairkeys | pairvalues |
---|---|
1 | WA |
1 | AC |
2 | WA |
2 | AC |
2 | WA |
my @c = uniq pairkeys pairgrep {$b eq 'AC'} @p; # => @c = (1, 2)
ここでは、@p を pair化し $b (pairvalues 側)を 'AC' で grep します。
更に、pairkeys 側を取り出して uniq で重複を削除しています。
tuple 的な手法
同じく、AtCoder Beginner Contest 151 C - Welcome to AtCoder
use strict;
use warnings;
use 5.26.1;
use List::Util qw(pairs pairgrep pairkeys pairvalues uniq sum0);
my ($n, $m);
{
my $in = <STDIN>;
($n, $m) = split(" ", $in);
}
my @p;
for (my $i=0; $i<$m; $i++) {
@p = (@p, split " ", <STDIN>);
}
my @c = uniq pairkeys pairgrep {$b eq 'AC'} @p;
my %d;
for my $i (@c) {
$d{$i} = [1, 0];
}
for my $pair (pairs @p) {
if ($pair->value eq 'WA') {
if ($d{$pair->key}[0]) {
$d{$pair->key}[1]++;
}
} else {
$d{$pair->key}[0] = 0;
}
}
my $sum = 0;
for my $key (keys %d) {
$sum += $d{$key}[1];
}
say scalar @c, " ", $sum;
for my $i (@c) {
$d{$i} = [1, 0];
}
for my $pair (pairs @p) {
if ($pair->value eq 'WA') {
if ($d{$pair->key}[0]) { # => key 問目の AC フラグ
$d{$pair->key}[1]++; # => key 問目の WA カウント
ハッシュ %d の value 側に配列のリファレンスを渡すことにより、3つ以上の要素から成る「組」を生成しています。
feature プラグマ
こちらのQiita に詳しいのですが、先頭で、
use feature qw(say state bitwise);
と宣言すると、say state bitwise が使用可能となります。
説明 | |
---|---|
say | 末尾改行付き print |
state | 競プロとしては、変数の重複回避 |
bitwise | ビット演算子の拡張 |
use feature qw(say state bitwise);
sub count1 {
state $c = 0;
++$c;
}
sub count2 {
state $c = 0;
++$c;
}
say count1(); # => 1
say count1(); # => 2
say count2(); # => 1
say "1001" | "0010"; # => 1003
say "1001" |. "0010"; # => 1011
no feature qw(bitwise);
say "1001" | "0010"; # => 1011
まとめ
- やはりC++のチート具合が凄い
- でも Perlもいい線いっている
- tani-ro-hei さん、List::Util の pair を教えていただき、ありがとうございました。
参照したサイト
追記
product は階乗ではなく総乗でした。
各メジャーバージョンの Perl に同梱されている List::Util で使える関数一覧
use List::Util qw(reduce);
print reduce {$a * $b % 1000000007} 1..100; # => 437918130
競プロ目線ですと、reduce の方が使用頻度が高そうな気がします。