ICPCの問題をPerl 6で解いてみる
Higher-Order Perl: Transforming Programs with Programsを読んでいたらなんとなくPerl 6で遊びたくなってきたのでICPC関連の簡単な問題をいくつかPerl 6で解き直してみました。問題はACM/ICPC国内予選突破の手引きのリストのうち上からチョイス。
#! /usr/bin/pugs loop { my ($n, $r) = (in, in); last if $n == 0 and $r == 0; my @cards = (1..$n).reverse; for 1..$r { my ($p, $c) = (in, in); my @cut = @cards.splice($p-1, $c); unshift @cards, @cut; } @cards.shift.say; } exit; { my $line = ''; sub in { $line = =<> if $line eq ''; return $0 if $line ~~ s/\s*(\S+)\s*//; die "No more input"; } }
この入力用の in 関数は以降使いまわしです。
#! /usr/bin/pugs loop { my ($n, $q) = (in, in); last if $n == 0 and $q == 0; my %schedule; for 1..$n { for 1..in { %schedule{in}++; } } my $max = %schedule.keys.map:{ [ $^k, %schedule{$^k} ] }.reduce:{ $^x[1] > $^y[1] ?? $^x !! $^y }; say $max[1] >= $q ?? $max[0] !! 0; } exit; { my $line = ''; sub in { $line = =<> if $line eq ''; return $0 if $line ~~ s/\s*(\S+)\s*//; die "No more input"; } }
maxをreduceで求めてみるテスト。正直微妙。
#! /usr/bin/pugs loop { my $n = in; last if $n == 0; my ($w, $h) = (in, in); my %field; %field{ join ',', in, in } = 1 for 1..$n; my ($s, $t) = (in, in); my $max = 0; for 1..$w -> $x { for 1..$h -> $y { my $count = 0; for 0..$s-1 -> $dx { for 0..$t-1 -> $dy { $count += %field{ join ',', $x+$dx, $y+$dy }; } } $max = $count if $count > $max; } } say $max; } exit; { my $line = ''; sub in { $line = =<> if $line eq ''; return $0 if $line ~~ s/\s*(\S+)\s*//; die "No more input"; } }
実直に。
#! /usr/bin/pugs my %table = < m 1000 c 100 x 10 i 1 >; my @keys_in_order = <m c x i>; { my $n = in; for 1..$n { my ($s1, $s2) = (in, in); my $sum = to_int($s1) + to_int($s2); for @keys_in_order -> $k { my $v = %table{$k}; my $q = int($sum / $v); $sum = $sum % $v; print $q if $q > 1; print $k if $q > 0; } say; } } exit; sub to_int ($str) { my $copy = $str; my $sum = 0; $sum += ($0 ne '' ?? $0 !! 1) * %table{$1} while $copy ~~ s/ (\d?) (<alpha>) //; return $sum; } { my $line = ''; sub in { $line = =<> if $line eq ''; return $0 if $line ~~ s/\s*(\S+)\s*//; die "No more input"; } }
regexの記法がかなり変わっていて分かりません。[a-z]でcharacter classは作れなくなったのか…。
#! /usr/bin/pugs my @p; for 2..1120 -> $x { push @p, $x if $x % all(@p) != 0; } loop { my ($n, $k) = (in, in); last if $n == 0 and $k == 0; solve($n, $k, 0).say; } exit; { my %cache; sub solve ($n, $k, $idx) { return 1 if $n == 0 and $k == 0; return 0 if $n == 0 or $k == 0; my $key = join ',', $n, $k, $idx; if not defined %cache{$key} { my $count = 0; for $idx..@p-1 -> $i { last if @p[$i] > $n; $count += solve($n - @p[$i], $k - 1, $i + 1); } %cache{$key} = $count; } return %cache{$key}; } } { my $line = ''; sub in { $line = =<> if $line eq ''; return $0 if $line ~~ s/\s*(\S+)\s*//; die "No more input"; } }
素数の配列が1行で作れるのは気持ちがいい。ジャンクションはなかなか使い勝手がいいですね。この問題を走らせると,実行速度が明らかに C >> Perl 5 >>>> Pugs なのが手に取るように分かって,Pugsで 1120 14 はメモ化しているのにも関わらず止まりません…。
#! /usr/bin/pugs my @table = ( [<. , ! ?>, ' '], [<a b c>], [<d e f>], [<g h i>], [<j k l>], [<m n o>], [<p q r s>], [<t u v>], [<w x y z>], ); { my $n = in; for 1..$n { my @x = split '', in; while @x { my $num = @x.shift or next; my $seq = 0; $seq++ while @x.shift; @table[$num-1][ $seq % @table[$num-1] ].print; } say; } } exit; { my $line = ''; sub in { $line = =<> if $line eq ''; return $0 if $line ~~ s/\s*(\S+)\s*//; die "No more input"; } }
Perl 5の qw() が <> で書けるようになった点は意外と便利。