スキップしてメイン コンテンツに移動

Project Euler - Problem 41

問題

  • 原文

    What is the largest n-digit pandigital prime that exists?

  • 日本語訳

    n桁のPandigitalな素数の中で最大の数を答えよ.

解答

ある数が3の倍数のとき、その各桁を足し合わせた数もまた3の倍数であり、その逆もいえます:

n = am-1am-2...a0
= am-1×10m-1 + am-2×10m-2 + ... + a0×100
= am-1×(1 + 999...9) + am-2×(1 + 99...9) + ... + a1×(1 + 9) + a0×1
= (am-1 + am-2 + ... + a0) + am-1×(999...9) + am-2×(99...9) + ... + a1×9
∴ nが3の倍数のとき、am-1 + am-2 + ... + a0は3の倍数

つまり1 + 2 + ... + mが3の倍数であったとすると、m桁のPandigital数の中に解は存在し得ないことが分かります。m = 8, 9のときがこの場合に該当するので、探索範囲を大きく減らせます。

Pandigital数を作る際に数値を重複なく選ぶため、Set::ObjectというCPANモジュールを使って簡単な集合演算を行っています。

#!/usr/bin/env perl;

use strict;
use warnings;
use feature qw/say state/;
use List::Util qw/sum/;
use List::MoreUtils qw/none/;
use Set::Object qw/set/;

sub is_prime($) {
  state %memos;
  my $n = shift;
  return 0 if $n < 2;
  return 1 if $n == 2;
  return 1 if $n == 3;
  return $memos{$n} if exists $memos{$n};
  $memos{$n} = none { $n % $_ == 0 } 2 .. sqrt $n;
}

my $prime_tails = set(1, 3, 7, 9);

sub max_pandigital_prime($;$$);
sub max_pandigital_prime($;$$) {
  my ($ndigits, $num, $rest_digits) = @_;
  $num //= '';
  $rest_digits //= set(1 .. $ndigits);

  return is_prime $num ? $num : undef if $rest_digits->is_null;
  return undef if ($rest_digits * $prime_tails)->is_null;

  for my $n (sort { $b <=> $a } $rest_digits->members) {
    $rest_digits->remove($n);
    my $answer = max_pandigital_prime($ndigits - 1, $num . $n, $rest_digits);
    return $answer if defined $answer;
    $rest_digits->insert($n);
  }
  return undef;
}

my $answer;
for my $ndigits (reverse 1 .. 9) {
  next if sum(1 .. $ndigits) % 3 == 0;
  last if defined ($answer = max_pandigital_prime($ndigits));
}
say $answer;

コメント

このブログの人気の投稿

京大テキストコーパスのパーサを書いた

要旨CaboCha やなんかの出力形式であるところの京大テキストコーパス形式のパーサモジュールを Perl で書いたので紹介します。GithubTarball on Github Ppagesこれを使うと例えば CaboCha の出力した係り受け関係を Perl のオブジェクトグラフとして取得できます。使用例単なる文節区切りの例。#!/usr/bin/env perl use v5.18; use utf8; use IPC::Open3; use Parse::KyotoUniversityTextCorpus; use Parse::KyotoUniversityTextCorpus::MorphemeParser::MeCab; use Symbol qw//; my ($in, $out, $err); my $pid; BEGIN { ($in, $out, $err) = (Symbol::gensym, Symbol::gensym, Symbol::gensym); $pid = open3($in, $out, $err, cabocha => '-f1'); } END { close $out; close $err; waitpid $pid => 0 if defined $pid; } binmode STDOUT, ':encoding(utf8)'; binmode $in, ':encoding(utf8)'; binmode $out, ':encoding(utf8)'; my $parser = Parse::KyotoUniversityTextCorpus->new( morpheme_parser => Parse::KyotoUniversityTextCorpus::MorphemeParser::MeCab->new, ); say $in '星から出るのに、その子は渡り鳥を使ったんだと思う。'; say $in '出る日の朝、自分の星の片付けをした。'; close $in; my $sentence_trees = $parser->…

Algorithm::LibLinear の紹介

Notice: This article is outdated. Please refer an updated English tutorial. 要旨かなり前になりますが、Algorithm::LibLinear という Perl モジュールを書きました。CPANGithubこれを使うと線形分類器などが高速に学習できます。テキストや画像の分類が応用として期待されます。LIBLINEAR についてLIBLINEARLIBSVM と同じ台湾国立大学の Chih-Jen Lin 教授のチームが公開しているオープンソースの機械学習パッケージです。 関数のロジスティック回帰、サポートベクター回帰及び線形 SVM による多クラス分類を行うことができます。LIBSVM と違ってカーネル関数を使うことはできませんが、はるかに高速に動作します。Algorithm::LibLinear についてLIBLINEAR には C++ で書かれたライブラリと、その機能を使って機械学習と分類・関数回帰を行うコマンドラインユーティリティが含まれています。 Algorithm::LibLinear はライブラリの機能を Perl からオブジェクト指向的に利用できるようにした上で、コマンドラインユーティリティの一部機能をライブラリ化して Perl で再実装したものです。使い方分類問題を解くときは、訓練データセットの読み込み・スケーリング学習器パラメータの設定分類器の訓練実データの分類という手順で行います。訓練データセットの読み込み正解ラベルのついたデータを大量に用意して学習させます。LIBSVM 形式のデータを読み込むか:my $data_set = Algorithm::LibLinear::DataSet->load(string => <<'EOD'); 1 1:0.1 2:0.1 4:0.1 -1 1:0.1 2:-0.1 3:0.1 ... EOD HashRef として表現されたデータを使います:my $data_set = Algorithm::LibLinear::DataSet->new(data_set => [ +{ feature => +{ 1 => 0.1, 2 => 0.1, 4 =…

Perl 5 to 6 - 正規表現(またの名をルール)

これはMoritz Lenz氏のWebサイトPerlgeek.deで公開されているブログ記事"Perl 5 to 6" Lesson 07 - Regexes (also called "rules")の日本語訳です。原文はCreative Commons Attribution 3.0 Germanyに基づいて公開されています。本エントリにはCreative Commons Attribution 3.0 Unportedを適用します。Original text: Copyright© 2008-2010 Moritz LenzJapanese translation: Copyright© 2011 SATOH KoichiNAME"Perl 5 to 6" Lesson 07 - 正規表現(またの名をルール)SYNOPSISgrammar URL { token TOP { <schema> '://' [<ip> | <hostname> ] [ ':' <port>]? '/' <path>? } token byte { (\d**{1..3}) <?{ $0 < 256 }> } token ip { <byte> [\. <byte> ] ** 3 } token schema { \w+ } token hostname { (\w+) ( \. \w+ )* } token port { \d+ } token path { <[ a..z A..Z 0..9 \-_.!~*'():@&=+$,/ ]>+ } } my $match = URL.parse('http://perl6.org/documentation/')…