Problem: 2520, 1'den 10'a kadar olan sayıların her birine kalansız olarak bölünebilen en küçük sayıdır. 1'den 20'ye kadar olan tüm sayılara tam bölünebilen en küçük pozitif sayı kaçtır?

1776118615560.webp


Bu tür problemlerde 2 tür senaryomuz var. İlk senaryomuz sayıların 1'den başlayıp ardışık olarak gitmesi, ikinci ihtimal m'den başlayıp n'ye kadar ardışık olarak gitmesi. Öncelikle matematiksel çözümünü anlatıp sonrasında scriptler ile çözeceğiz.

Problem ilk senaryomuza uyuyor. Bu koşullarda teorimiz şu: "Biz 1, 2, 3, ..., 20 sayılarının EKOK'unu arıyoruz. Bu EKOK sayısının içinde bulunabilecek asal çarpanlar, mecburen 20'den küçük veya ona eşit olan asal sayılardır (2, 3, 5, 7, 11, 13, 17, 19). Çünkü 20'den büyük bir asal sayı (örneğin 23), 1 ile 20 arasındaki hiçbir sayının çarpanı olamaz.". Bunun hesabını da 20'ye kadar olan asal sayıların, 20'yi geçmeyen en büyük kuvvetlerini çarparak yapabiliriz. Adımlarımız:

  • 20'den küçük asal sayıları belirleyelim.
  • Her bir asal sayının 20'yi aşmayan en büyük kuvvetini bulalım:
    • 2 için: 2^4 = 16 (Çünkü 2^5 = 32, 20'yi geçer)
    • 3 için: 3^2 = 9 (Çünkü 3^3 = 27, 20'yi geçer)
    • 5 için: 5^1 = 5 (Çünkü 5^2 = 25, 20'yi geçer)
    • Diğer asalların (7, 11, 13, 17, 19) sadece ilk kuvetleri 20'den küçüktür.
  • Bulduğumuz en büyük kuvvetleri birbiriyle çarpalım:
    • 16*9*5*7*11*13*19=232792560

İkinci senaryomuz ise sayıların m'den n'ye ardışık gitmesi gerektiğini belirtmiştik. Bu yöntemin adımları:
  • Elimizdeki 20 sayının her birini bölen asal çarpanları tespit edelim.
  • Ortaya çıkan tüm asal çarpanlar için, o aralıktaki herhangi bir sayıda bulunan en yüksek üslü ifadeyi alalım.
    • Örneğin: Aralıktaki sayılardan biri 48 ise asal çarpanları 2^4,3 olur ve bir diğeri 54 ise 2,3^3 ise, EKOK hesabına 2^4 ve 3^3'ü dahil etmemiz gerekir.
  • Seçilen en yüksek üslü ifadeleri çarparak sonuca ulaşırız.
Genel Sonuç (Bu kısmı matematiksel ifadeler olduğu için LibreOffice Math programını kullanarak oluşturdum. Forumun Latex eklentisi ne yazık ki bir süreliğine çalışmıyor)

Kod:
Matematiksel olarak 1'den n'e kadar olan ardışık sayıların EKOK'u (L_n), her bir p <= n asal sayısı için şu şekilde ifade edilir:

L_n = prod from { p <= n } p^{ lfloor log_p(n) rfloor }

1776116853726.webp


Özetle; sayıları tek tek asal çarpanlarına ayırıp en büyük üsleri seçmek uzun sürer. Ancak biz mantıken biliyoruz ki; hiçbir asalın kuvveti, aralığın son sayısını (örneğimizde 20) geçemez. Bu yüzden sadece asal sayıların 20'yi aşmayan en büyük kuvvetlerini bulup çarpmak, bize doğrudan kesin ve ispatlanmış sonucu verir.



(Rust ve C CLion'ın üzerinde Github Copilot kullanılarak hazırlanmıştır.)

1'den n'e kadar olan sayıların en küçük ortak katını bulan örnek fonksiyonlar

Python:
import math

def asal_mi(sayi): # Öncelikle sayıların asal olup olmadığını kontrol edeceğimiz fonksiyonu yazıyoruz.
    if sayi < 2:
        return False
    for i in range(2, math.isqrt(sayi) + 1):
        if sayi % i == 0:
            return False
    return True

def ilk_n_sayinin_ekoku(n): # 1'den n'ye kadar olan sayıların en küçük ortak katı
    if n < 1:
        return 1

    ekok = 1
    for p in range(2, n + 1):
        if asal_mi(p):
            # Logaritma yerine basit bir döngü ile en yüksek kuvveti bulabiliriz
            # Böylece ondalıklı sayılardan doğabilecek hataları engelleyebiliyoruz.
            en_yuksek_kuvvet = p
            while en_yuksek_kuvvet * p <= n:
                en_yuksek_kuvvet *= p

            ekok *= en_yuksek_kuvvet

    return ekok


n_degeri = 20
sonuc = ilk_n_sayinin_ekoku(n_degeri)
print(sonuc)


Kod:
fn main() {
    let n_degeri: u64 = 20;
    let sonuc = ilk_n_sayinin_ekoku(n_degeri);
    println!("{}", sonuc);
}

fn asal_mi(sayi: u64) -> bool { // Asallık kontrolü yapan fonksiyonumuz
    if sayi < 2 { return false; }
    let limit = (sayi as f64).sqrt() as u64;
    for i in 2..=limit {
        if sayi % i == 0 { return false; }
    }
    true
}

fn ilk_n_sayinin_ekoku(n: u64) -> u64 {
    if n < 1 { return 1; }
    let mut ekok: u64 = 1;
 
    for p in 2..=n {
        if asal_mi(p) {
            let mut en_yuksek_kuvvet = p;
            while en_yuksek_kuvvet * p <= n {
                en_yuksek_kuvvet *= p;
            }
            ekok *= en_yuksek_kuvvet;
        }
    }
    ekok
}

C:
#include <stdio.h>
#include <stdbool.h>
#include <math.h>

bool asal_mi(unsigned long long sayi) {
    if (sayi < 2) return false;
    unsigned long long limit = sqrt(sayi);
    for (unsigned long long i = 2; i <= limit; i++) {
        if (sayi % i == 0) return false;
    }
    return true;
}

unsigned long long ilk_n_sayinin_ekoku(unsigned long long n) {
    if (n < 1) return 1;
    unsigned long long ekok = 1;
 
    for (unsigned long long p = 2; p <= n; p++) {
        if (asal_mi(p)) {
            unsigned long long en_yuksek_kuvvet = p;
            while (en_yuksek_kuvvet * p <= n) {
                en_yuksek_kuvvet *= p;
            }
            ekok *= en_yuksek_kuvvet;
        }
    }
    return ekok;
}

int main() {
    unsigned long long n_degeri = 20;
    unsigned long long sonuc = ilk_n_sayinin_ekoku(n_degeri);
    printf("%llu\n", sonuc);
    return 0;
}


m'den n'e kadar olan sayıların en küçük ortak katı

Python:
import math
from functools import reduce


def araligin_ekoku(baslangic, bitis):
    #Belirli bir aralıktaki (başlangıç ve bitiş dahil) ardışık sayıların EKOKunu bulur.
    sayilar = range(baslangic, bitis + 1)

    # reduce fonksiyonu, math.lcm işlemini listedeki tüm sayıları zincirleme uygular.
    # Örneğin lcm(lcm(sayi1, sayi2), sayi3) ... şeklinde devam eder.
    ekok_sonuc = reduce(math.lcm, sayilar)

    return ekok_sonuc


baslangic_degeri = 1
bitis_degeri = 20
sonuc_2 = araligin_ekoku(baslangic_degeri, bitis_degeri)

print(sonuc_2)

Kod:
fn main() {
    let baslangic: u64 = 1;
    let bitis: u64 = 20;
    let sonuc = araligin_ekoku(baslangic, bitis);
    println!("{}", sonuc);
}

fn ebob(mut a: u64, mut b: u64) -> u64 {
    while b != 0 {
        let gecici = b;
        b = a % b;
        a = gecici;
    }
    a
}

fn iki_sayinin_ekoku(a: u64, b: u64) -> u64 {
    if a == 0 || b == 0 { return 0; }
    // Taşmayı önlemek için önce bölüp sonra çarpıyoruz
    (a / ebob(a, b)) * b
}

fn araligin_ekoku(baslangic: u64, bitis: u64) -> u64 {
    let mut guncel_ekok = baslangic;
    for i in (baslangic + 1)..=bitis {
        guncel_ekok = iki_sayinin_ekoku(guncel_ekok, i);
    }
    guncel_ekok
}

C:
#include <stdio.h>

unsigned long long ebob(unsigned long long a, unsigned long long b) {
    while (b != 0) {
        unsigned long long gecici = b;
        b = a % b;
        a = gecici;
    }
    return a;
}

unsigned long long iki_sayinin_ekoku(unsigned long long a, unsigned long long b) {
    if (a == 0 || b == 0) return 0;
    // Yine taşmayı önlemek için aynı işlemi yapıyoruz
    return (a / ebob(a, b)) * b;
}

unsigned long long araligin_ekoku(unsigned long long baslangic, unsigned long long bitis) {
    unsigned long long guncel_ekok = baslangic;
    for (unsigned long long i = baslangic + 1; i <= bitis; i++) {
        guncel_ekok = iki_sayinin_ekoku(guncel_ekok, i);
    }
    return guncel_ekok;
}

int main() {
    unsigned long long baslangic = 1;
    unsigned long long bitis = 20;
    unsigned long long sonuc = araligin_ekoku(baslangic, bitis);
    printf("%llu\n", sonuc);
    return 0;
}



Nasıl hesaplandığını merak ettiğiniz, alternatif yol aradığınız Project Euler veya başka platformlardaki problemleri yazarsanız yardımcı olmaya çalışırım. İyi Sosyaller dilerim.