LoginSignup
4
0

More than 3 years have passed since last update.

Perl AtCoderのアップデートを先取りしてライバルに差をつけよう(List::Util他)

Last updated at Posted at 2020-03-06

はじめに

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

product.pl
use List::Util qw(product);
print product 1..6; # => 6! = 720
print product (2, 2, 2, 2, 3, 3, 5); # => 720

階乗です 総乗でした

reduce.pl
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

C.pl
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
uniq.pl
my @c = uniq pairkeys pairgrep {$b eq 'AC'} @p; # => @c = (1, 2)

ここでは、@ppair化し $b (pairvalues 側)を 'AC' で grep します。
更に、pairkeys 側を取り出して uniq で重複を削除しています。

tuple 的な手法

同じく、AtCoder Beginner Contest 151 C - Welcome to AtCoder

tuple.pl
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;
tuple.pl
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.pl
use feature qw(say state bitwise);

と宣言すると、say state bitwise が使用可能となります。

説明
say 末尾改行付き print
state 競プロとしては、変数の重複回避
bitwise ビット演算子の拡張
feature.pl
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 で使える関数一覧

mod.pl
use List::Util qw(reduce);
print reduce {$a * $b % 1000000007} 1..100; # => 437918130

競プロ目線ですと、reduce の方が使用頻度が高そうな気がします。

4
0
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
4
0