modular_fibonacci_polynomial_2.pl 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 11 October 2017
  4. # https://github.com/trizen
  5. # Algorithm for computing a Fibonacci polynomial modulo m.
  6. # (Sum_{k=1..n} (fibonacci(k) * x^k)) (mod m)
  7. # See also:
  8. # https://projecteuler.net/problem=435
  9. use 5.020;
  10. use strict;
  11. use warnings;
  12. use experimental qw(signatures);
  13. use ntheory qw(addmod mulmod powmod factor_exp chinese);
  14. sub modular_fibonacci_polynomial ($n, $x, $m) {
  15. my @chinese;
  16. foreach my $p (factor_exp($m)) {
  17. my $pp = $p->[0]**$p->[1];
  18. my $sum = 0;
  19. my ($f1, $f2) = (0, 1);
  20. my @array;
  21. foreach my $k (1 .. $n) {
  22. $sum = addmod($sum, mulmod($f2, powmod($x, $k, $pp), $pp), $pp);
  23. push @array, $sum;
  24. ($f1, $f2) = ($f2, addmod($f1, $f2, $pp));
  25. if ($f1 == 0 and $f2 == 1 and $k > 20 and
  26. join(' ', @array[9 .. $#array/2])
  27. eq join(' ', @array[$#array/2 + 10 .. $#array])
  28. ) {
  29. $sum = $array[($n % $k) - 1];
  30. last;
  31. }
  32. }
  33. push @chinese, [$sum, $pp];
  34. }
  35. return chinese(@chinese);
  36. }
  37. say modular_fibonacci_polynomial(7, 11, 100000); #=> 57683
  38. say modular_fibonacci_polynomial(10**15, 13, 6227020800); #=> 4631902275