Informatyczny kącik olimpijski
Liczby
W tym miesiącu omówimy zadanie Liczby, które pojawiło się podczas rundy 72. na portalu codeforces.com.
W zadaniu należy, mając dane liczby naturalne wyznaczyć liczbę liczb naturalnych w przedziale
których najmniejszym dzielnikiem, większym od
jest
Zauważmy najpierw, że wystarczy umieć obliczać wyniki dla przedziałów postaci
ponieważ wynik dla przedziału
jest różnicą wyników dla przedziałów
i
Ponadto, jeśli
nie jest liczbą pierwszą, to wynik jest równy 0, ponieważ jeśli liczba jest podzielna przez
to jest też podzielna przez każdy dzielnik
a skoro
nie jest pierwsza, to ma dzielnik większy od
i mniejszy od
Załóżmy teraz, że
jest pierwsza. Zadanie można rozwiązać w czasie
wyznaczając dla każdej liczby z przedziału
jej najmniejszy dzielnik, większy od 1, za pomocą sita Eratostenesa. Rozwiązanie to dla
jest dalece niewystarczające. Zauważmy, że można je łatwo usprawnić. Każda liczba, której najmniejszy dzielnik jest równy
jest postaci
gdzie
nie ma dzielników większych od
i mniejszych od
Wystarczy zatem zliczyć takie
-y z przedziału
które nie mają dzielników pierwszych mniejszych od
Można to zrobić, iterując kolejne liczby pierwsze mniejsze od
i zaznaczając w tablicy liczby podzielne przez którąś z nich.
Rozwiązanie to wykona dla każdej liczby pierwszej mniejszej od
operacji, czyli łącznie

Dla rozwiązanie takie jest wystarczające. Jeśli natomiast
jest mniejsze od
to liczb pierwszych mniejszych od
jest nie więcej niż
Niech teraz
oznacza zbiór liczb podzielnych przez
oraz
leżących w przedziale
Naszym zadaniem jest obliczenie
![{x ∈[1,n] k x}∖ ⎛ A . ⎝ p>P,p@k](/math/temat/informatyka/algorytmy/2017/11/25/Liczby/14x-d7d892ccd540d7223422dfe09c1914ea7aedc6e3-dm-33,33,33-FF,FF,FF.gif)
Możemy to zrobić, korzystając z zasady włączeń i wyłączeń. W tym celu musimy umieć obliczyć Jest to zbiór liczb podzielnych przez
leżących w przedziale
czyli ma
elementów.
Całe rozwiązanie działa w czasie

Na to zadanie można też spojrzeć inaczej. Niech będzie liczbą liczb w przedziale
które nie mają dzielników większych od
i mniejszych od
Wykażemy, że

Istotnie, liczb nie większych od których najmniejszym dzielnikiem jest
jest
ponieważ każda taka liczba jest postaci
gdzie
nie ma dzielników większych od
i mniejszych od
a
czyli
Wszystkich liczb w przedziale
jest
a każda z nich albo ma dzielnik pierwszy mniejszy od
wówczas zostanie odjęta dokładnie raz, dla
będącego jej najmniejszym dzielnikiem pierwszym, albo nie ma i wtedy nie zostanie odjęta. Liczba liczb w przedziale
których najmniejszym dzielnikiem jest
jest równa
Zadanie można rozwiązać, obliczając wartość funkcji
rekurencyjnie korzystając z tego wzoru. Niech
będą kolejnymi liczbami pierwszymi, a
liczbą operacji wykonanych przez algorytm dla liczby pierwszej
Wówczas
Rozwiązaniem tego równania jest
czyli całe rozwiązanie będzie działało w czasie
co jest zdecydowanie za wolne.
Rozwiązanie to można łatwo przyspieszyć. Wystarczy zauważyć, że jeśli to jedyną liczbą w przedziale
niemającą dzielników większych od
i mniejszych od
jest
więc
i w każdym wywołaniu rekurencyjnym obliczającym wynik dla
zwracać
bez dalszych wywołań rekurencyjnych. Wykażemy, że rozwiązanie z tą optymalizacją obliczające
wykona co najwyżej
wywołań rekurencyjnych. Rozważmy gałąź w drzewie rekursji, w której algorytm wykonał kolejno dzielenia przez
Oznacza to, że w przedostatnim wywołaniu obliczał
Skoro nie zwrócił wyniku od razu, tylko wykonał następne wykonanie rekurencyjne, to
skąd wynika, że
czyli
Algorytm w danym wywołaniu przegląda jedynie liczby pierwsze, mniejsze od poprzedniej, zatem
skąd otrzymujemy
Liczby
są pierwsze, więc dla różnych wywołań rekurencyjnych iloczyny
będą parami różne, więc liczba tych wywołań nie przekroczy
Prezentowane rozwiązanie potrzebuje listy liczb pierwszych mniejszych od Można ją, oczywiście, wyznaczyć, używając sita Eratostenesa, w czasie
Ostatecznie, całe rozwiązanie obliczające
działa w czasie