571 Super Pandigital Numbers -- v2.pl 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 20 August 2017
  4. # https://github.com/trizen
  5. # https://projecteuler.net/problem=571
  6. # Brute-force solution, with some optimizations.
  7. # Runtime: ~12 minutes.
  8. use 5.010;
  9. use strict;
  10. use warnings;
  11. use List::Util qw(all);
  12. use ntheory qw(fromdigits);
  13. use experimental qw(signatures);
  14. use Algorithm::Combinatorics qw(variations);
  15. my $base = shift(@ARGV) // 12; # pandigital in all bases 2..$base
  16. my $first = 10; # generate first n numbers
  17. my @digits = (1, 0, 2 .. $base - 1);
  18. my @bases = reverse(2 .. $base - 1);
  19. my $sum = 0;
  20. my $iter = variations(\@digits, $base);
  21. sub is_8_pandigital ($n) {
  22. my $found = 0;
  23. while ($n > 0) {
  24. $found |= 1 << ($n & 7);
  25. $n >>= 3;
  26. }
  27. $found == (1 << 8) - 1;
  28. }
  29. sub is_pandigital ($n, $base) {
  30. my $found = 0;
  31. while ($n > 0) {
  32. $found |= 1 << ($n % $base);
  33. $n = int($n / $base);
  34. }
  35. $found == (1 << $base) - 1;
  36. }
  37. while (defined(my $t = $iter->next)) {
  38. if ($t->[0]) {
  39. my $v = fromdigits($t, $base);
  40. if (is_8_pandigital($v) and all { is_pandigital($v, $_) } @bases) {
  41. say "Found: $v";
  42. $sum += $v;
  43. last if --$first == 0;
  44. }
  45. }
  46. }
  47. say "Sum: $sum";