# https://perlmonks.org/?node_id=11142871 use v5.12; use warnings; use Data::Dump qw/pp dd/; my $range = 32; my %sieves; use constant DBG => 0; sub get_sieve { my ( $prime, $range ) = @_; my @sieve = 0; # p^0 = 1 my @pos = (0); while ( @sieve < 2*$range ) { @sieve = (@sieve) x $prime ; $sieve[-1]++; push @pos, @sieve-1; } pop @pos; # forget edge return { prime => $prime, sieve => [ @sieve[0 .. 2*$range-1] ], sieve_pos => \@pos, sieve_max => @pos-1, }; } sub valid_set_lanx { warn "call:",pp \@_ if DBG; my($p, $a_known) = @_; my $h_sieve_cache = $sieves{$p} //= get_sieve($p,$range); my ($a_sieve, $a_sieve_pos, $sieve_max) = @{$h_sieve_cache}{qw/sieve sieve_pos sieve_max/}; warn pp $h_sieve_cache if DBG; # --- find max_known my @known = @$a_known; my $max_known = 0; my $max_pos = 0; my $idx = 0; for my $e (@known) { next unless defined $e; if ($e > $max_known) { $max_known = $e; $max_pos = $idx; } } continue { $idx++; } # --- adjust into sieve range if ($max_known > $sieve_max) { $max_known = $sieve_max; $known[$max_pos] = $max_known; } my $idx_sieve = $a_sieve_pos->[$max_known]- $max_pos; if ( DBG ) { #warn pp [\@known,$a_sieve,$max_known,$a_sieve_pos->[$max_known],$idx_sieve,$max_pos]; warn (". "x $idx_sieve, join " ", map { $_ // "?" } @known); warn "@$a_sieve"; } my $ok = 1; for my $e (@known) { #warn (($a_sieve->[$idx_sieve] //"?"), " - ", ($e//"?")) if DBG; next unless defined $e; $ok=0 if $e != $a_sieve->[$idx_sieve] } continue { $idx_sieve++ } return $ok; } # test the examples: expect [yes, yes, no, no] print valid_set_lanx(@$_) ? "yes\n" : "no\n" for ( [ 2, [0, 1, 0, 2, 0]], [ 2, [1, 0, 5, 0, 1]], [ 2, [2, undef, undef, undef, 2]], [ 3, [1, 0, 0, 1, 0, 0, 1]], [ 2, [1, 0, 8, 0, 1]], );