754 Product of Gauss Factorials -- v3.pl 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #!/usr/bin/perl
  2. # Product of Gauss Factorials
  3. # https://projecteuler.net/problem=754
  4. # See also:
  5. # https://oeis.org/A001783
  6. # WARNING: requires ~3 GB of RAM.
  7. # Somehow, this approach seems to be incorrect...
  8. use 5.020;
  9. use strict;
  10. use warnings;
  11. use experimental qw(signatures);
  12. use ntheory qw(:all);
  13. use List::Util qw(uniq);
  14. sub g ($n, $m) {
  15. my $r = 0;
  16. foreach my $pp (factor_exp($n)) {
  17. my $p = $pp->[0];
  18. my $ndp = divint($n, $p);
  19. $r = gcd($r, divmod(factorialmod($n, $m), mulmod(powmod($p, $ndp, $m), factorialmod($ndp, $m), $m), $m));
  20. return $r if ($r == 1);
  21. }
  22. return $r;
  23. }
  24. sub G ($n, $m) {
  25. my $r = 1;
  26. foreach my $k (2 .. $n) {
  27. $r = mulmod($r, g($k, $m), $m);
  28. }
  29. return $r;
  30. }
  31. sub G2 ($N, $m) {
  32. my $r = 1;
  33. my $nfac = 1;
  34. my @facmod = (1);
  35. foreach my $k (1 .. $N) {
  36. $nfac = mulmod($nfac, $k, $m);
  37. push @facmod, $nfac;
  38. }
  39. forfactored {
  40. my $n = $_;
  41. my $g = 0;
  42. foreach my $p (uniq(@_)) {
  43. if ($p == $n) {
  44. $g = $facmod[$p-1];
  45. }
  46. else {
  47. my $ndp = divint($n, $p);
  48. $g = gcd($g, divmod($facmod[$n], mulmod(powmod($p, $ndp, $m), $facmod[$ndp], $m), $m));
  49. last if ($g == 1);
  50. }
  51. }
  52. $r = mulmod($r, $g, $m);
  53. } 2, $N;
  54. return $r;
  55. }
  56. use Test::More tests => 6;
  57. is(g(10, 1_000_000_007), 189);
  58. is(G(10, 1_000_000_007), 331358692);
  59. is(G2(10, 1_000_000_007), 331358692);
  60. is(G2(1e2, 1_000_000_007), 777776709);
  61. is(G2(1e3, 1_000_000_007), 297877340);
  62. is(G2(1e4, 1_000_000_007), 517055464);
  63. is(G2(1e5, 1_000_000_007), 516871211);
  64. #say G2(1e4, 1_000_000_007); # takes 0.1 seconds
  65. #say G2(1e5, 1_000_000_007); # takes 0.6 seconds
  66. #say G2(1e6, 1_000_000_007); # takes 5 seconds
  67. #say G2(1e7, 1_000_000_007); # takes 53 seconds
  68. say "\n:: Computing: G(10^8)";
  69. say G2(1e8, 1_000_000_007);