[英]Number theory algorithms. Most divisors on the segment
我正在尋找一種有效的算法來解決以下問題。 讓d(n)
表示的正除數的數n
其中n
是正整數。 我們得到了一些1 <= a <= b <= 10^18
,任務是在段[a..b]
上找到d
最大值,並且(可能我們需要更復雜的算法)來查找最大化d
值的數字。
前段時間我在免費訪問中找到了以下代碼: http : //ideone.com/qvxPj
unsigned long long n, res;
int p, primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 51, 53, 59, 61, 67, 71};
unsigned long long mul(unsigned long long a, unsigned long long b){
unsigned long long res = 0;
while (b){
if (b & 1LL) res = (res + a);
if (res >= n) return 0;
a = (a << 1LL);
b >>= 1LL;
}
return res;
}
void backtrack(int i, int lim, unsigned long long val, unsigned long long r){
if (r > res) res = r;
if (i == p) return;
int d;
unsigned long long x = val;
for (d = 1; d <= lim; d++){
x = mul(x, primes[i]);
if (x == 0) return;
backtrack(i + 1, d, x, r * (d + 1));
}
}
int main(){
p = sizeof(primes) / sizeof(int);
while (scanf("%llu", &n) != EOF){
res = 0;
backtrack(0, 100, 1, 1);
printf("Maximum number of divisors of any number less than %llu = %llu\n", n, res);
}
return 0;
}
如果有人向我解釋它是如何工作的,我將非常高興,因為(至於我)這個程序運行得非常快。
在此先感謝您的幫助。
它迭代所有數字,如下所示:
num = P1^D1 * P2^D2 * P3^D3 * ... * Ps^Ds
constraints:
Pi <= 71
1 <= Di <= 100
sequence (Pi) is a sorted list of first s primes
sequence (Di) is nonincreasing
num <= n
讓我們檢查第一個約束。 假設最小最優數具有素因子q> 71 。 如果任何質數p <= 71未在此數中使用的話,可以在相同的功率p替換Q值 。 顯然,除數的數量將保持不變,但數量會減少 - >矛盾。 然后沒有未使用的素數低於71.但是所有素數高達71的產品已經非常龐大,我們考慮的數量必須大於64位n 。 那是不可能的。
現在讓我們解釋第二個和第三個約束。 假設我們的最小最優數在其因子分解中具有素數q ,但是沒有一些素數p ,其中p <q 。 然后我們可以用p以相同的順序替換q ,數字將具有相同數量的除數,但它會變得更少 - >矛盾。 這意味着所尋求的最優(最小)數的因式分解中的所有素數必須恰好是第一個素數。 使用的素數組中不能有空洞。 BTW, Di <= 100是顯而易見的,因為即使2 ^ 100也不適合64位整數。
現在我們要解釋第四個約束。 假設某些i的 D [i] <D [i + 1] 。 然后,我們可以取代P [I] ^ d [I] * P [I + 1] ^ d [I + 1] P [I] ^ d [I + 1] * P [I + 1] ^ d [I ] ,數字會變小。 例如,用5 ^ 3 * 7 ^ 2替換5 ^ 2 * 7 ^ 3:除數的數量相同,但結果更小。 顯然,如果我們搜索最小的最優數,我們也可以安全地假設這個條件。
現在讓我們考慮一下代碼。 mul
是一個計算a和b的乘積的小函數。 它是通過一個有趣的二進制程序計算的。 此過程的主要原因是:如果乘積大於n ,則函數返回0.此過程僅防止溢出,否則可能發生。
最后,我們得backtrack
。 這是一種通常的遞歸搜索。 val
是當前數字, r
是它的除數數, i
顯示我們現在要添加的素數的索引,每個素數的lim
限制功率為100.在一開始你看到當前最佳答案的更新(存儲在res
)和硬停止條件(使用的所有質數)。
然后有一個循環檢查當前素數的每個冪。 它從功率1開始,因為禁止零功率。 它維持x
當前數字,並在每次迭代時將其乘以Pi以增加功率。 如果x
大於n ,則立即停止。 最后,它調用自己以搜索下一個素數。
作為@stgatilov答案的補充,我將證明選擇將素數限制為少於或等於71的素數。
我使用稍微修改過的代碼版本來記錄最大數量的除數。 對於1000000000000000000或999999999999999999,我得到:
897612484786617600 = 2 8 * 3 4 * 5 2 * 7 2 * 11 * 13 * 17 * 19 * 23 * 29 * 31 * 37
共有103680個除數。
這意味着對於所有18個十進制數字的數字,沒有涉及大於37的素數是找到具有最大除數的整數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.