-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathcount_of_inverse_tau_in_range.pl
More file actions
144 lines (107 loc) · 3.55 KB
/
Copy pathcount_of_inverse_tau_in_range.pl
File metadata and controls
144 lines (107 loc) · 3.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/perl
# Daniel "Trizen" Șuteu
# Date: 14 May 2026
# https://github.com/trizen
# Count the numbers in a given range [A,B] that have exactly `n` divisors.
use 5.036;
use ntheory 0.74 qw(:all);
prime_precalc(1e7);
sub count_prime_signature_numbers($n, $prime_signature) {
my $k = scalar(@$prime_signature);
if ($k == 0) {
return 1 if (1 <= $n);
return 0;
}
$n >= 1 || return 0;
my $sum_e = vecsum(@$prime_signature) || return 0;
if ($sum_e > logint($n, 2)) {
return 0;
}
my $count = 0;
my @sorted_sig = sort { $b <=> $a } @$prime_signature;
sub ($m, $lo, $rem_sig, $rem_sum, $j = 0) {
my $k = scalar(@$rem_sig);
my $hi = rootint(divint($n, $m), $rem_sum);
if ($lo > $hi) {
return;
}
if ($k == 1) {
$count = addint($count, prime_count($hi) - $j);
return;
}
my @seen;
for my $i (0 .. $#$rem_sig) {
my $e = $rem_sig->[$i];
next if $seen[$e]++;
my $local_j = $j;
my @new_sig = @$rem_sig;
splice(@new_sig, $i, 1);
if ($k == 2) {
my $e2 = $new_sig[0];
forprimes {
my $t = mulint($m, powint($_, $e));
my $u = rootint(divint($n, $t), $e2);
$count = addint($count, prime_count($u) - ++$local_j);
} $lo, $hi;
}
else {
my $new_sum = $rem_sum - $e;
for (my $p = $lo ; $p <= $hi ;) {
my $t = mulint($m, powint($p, $e));
my $r = next_prime($p);
__SUB__->($t, $r, \@new_sig, $new_sum, ++$local_j);
$p = $r;
}
}
}
}->(1, 2, \@sorted_sig, $sum_e);
return $count;
}
sub count_prime_signature_numbers_in_range($A, $B, $signature) {
my $term_1 = count_prime_signature_numbers($A - 1, $signature);
my $term_2 = count_prime_signature_numbers($B, $signature);
subint($term_2, $term_1);
}
sub tau_partitions($n, $max_sum_e) {
my @results;
my @divs = divisors($n);
shift(@divs); # remove divisor '1'
my $end = $#divs;
my @path;
sub ($target, $min_idx, $curr_sum_e) {
if ($target == 1) {
push @results, [@path];
return;
}
for my $i ($min_idx .. $end) {
my $d = $divs[$i];
my $e = $d - 1;
last if $d > $target;
last if ($curr_sum_e + $e > $max_sum_e);
if ($target % $d == 0) {
push @path, $e;
__SUB__->(divint($target, $d), $i, $curr_sum_e + $e);
pop @path;
}
}
}->($n, 0, 0);
return @results;
}
sub count_inverse_tau($A, $B, $n) {
my @signatures = tau_partitions($n, logint($B, 2));
my @counts;
foreach my $sig (@signatures) {
push @counts, count_prime_signature_numbers_in_range($A, $B, $sig);
}
vecsum(@counts);
}
count_inverse_tau(1, 462, 16) == 16 or die "error";
count_inverse_tau(1, powint(2, 9), 10) == 13 or die "error";
count_inverse_tau(1, powint(2, 40), 5040) == 103 or die "error";
count_inverse_tau(1e5, 1e5 + 500, 48) == 10 or die "error";
count_inverse_tau(100050, 100500, 48) == 10 or die "error";
# Number of k <= 2^(n-1) such that tau(k) = n
# https://oeis.org/A393179
foreach my $n (1 .. 32) {
say "a($n) = ", count_inverse_tau(1, powint(2, $n - 1), $n);
}