Powiedzmy, że mamy nieujemną liczbę całkowitą, która jest „mocna” (to znaczy „ciężka”), jeśli jej średnia wartość cyfry jest większa niż 7.
Liczba 6959 jest „duża”, ponieważ:
(6 + 9 + 5 + 9) / 4 = 7,5
Liczba 1234 nie jest, ponieważ:
(1 + 2 + 3 + 4) / 4 = 2,5
Napisz funkcję w dowolnym języku,
HeftyDecimalCount(a, b)
która, pod warunkiem, że dwie dodatnie liczby całkowite aib zwracają liczbę całkowitą wskazującą, ile „mocnych” liczb całkowitych znajduje się w przedziale [a..b], włącznie.
Na przykład, biorąc pod uwagę a = 9480 ib = 9489:
9480 (9+4+8+0)/4 21/4 = 5.25
9481 (9+4+8+1)/4 22/4 = 5.5
9482 (9+4+8+2)/4 23/4 = 5.75
9483 (9+4+8+3)/4 24/4 = 6
9484 (9+4+8+4)/4 25/4 = 6.25
9485 (9+4+8+5)/4 26/4 = 6.5
9486 (9+4+8+6)/4 27/4 = 6.75
9487 (9+4+8+7)/4 28/4 = 7
9488 (9+4+8+8)/4 29/4 = 7.25 hefty
9489 (9+4+8+9)/4 30/4 = 7.5 hefty
Dwie liczby w tym zakresie są „mocne”, więc funkcja powinna zwrócić 2.
Niektóre wytyczne:
- zakładamy, że ani a ani b nie przekracza 200 000 000.
- n-kwadratowe rozwiązanie będzie działać, ale będzie wolne - co najszybciej możemy rozwiązać?
Odpowiedzi:
Problem można rozwiązać w O (polilog (b)).
Definiujemy
f(d, n)
liczbę całkowitą do d cyfr dziesiętnych z sumą cyfr mniejszą lub równą n. Można zauważyć, że tę funkcję pełni formułaKorzystając z tego wzoru, możemy na przykład znaleźć liczbę liczb ciężkich w przedziale od 8000 do 8999
1000 - f(3, 20)
, ponieważ, ponieważ w tym przedziale jest tysiąc liczb, i musimy odjąć liczbę liczb z sumą cyfr mniejszą lub równą 28 jednocześnie przyjmując do wiadomości, że pierwsza cyfra już stanowi 8 w sumie cyfr.Jako bardziej złożony przykład przyjrzyjmy się liczbie ciężkich liczb w przedziale 1234..5678. Możemy najpierw przejść od 1234 do 1240 w krokach 1. Następnie przechodzimy od 1240 do 1300 w krokach 10. Powyższa formuła podaje nam liczbę ciężkich liczb w każdym takim przedziale:
Teraz przechodzimy od 1300 do 2000 w krokach co 100:
Od 2000 do 5000 w krokach co 1000:
Teraz musimy ponownie zmniejszyć rozmiar kroku, przechodząc z 5000 do 5600 w krokach co 100, z 5600 do 5670 w krokach co 10, a na koniec z 5670 do 5678 w krokach co 1.
Przykładowa implementacja Pythona (która tymczasem otrzymała niewielkie optymalizacje i testy):
Edycja : zastąpiono kod zoptymalizowaną wersją (która wygląda jeszcze brzydiej niż kod oryginalny). Naprawiłem również kilka narożnych skrzynek, gdy byłem przy tym.
heavy(1234, 100000000)
trwa około milisekundy na moim komputerze.źródło
binomial()
funkcja. Istnieje również kilka innych rzeczy, które można łatwo poprawić. Opublikuję aktualizację za kilka minut.f(d, n)
nie jest wywoływany dwukrotnie z tymi samymi parametrami podczas jednego uruchomienia programu.Powtarzaj i używaj permutacji.
Załóżmy, że definiujemy funkcję ogólną, która znajduje wartości między aib o ciężkości większej niż x:
Na przykładzie a = 8675 do b = 8689, pierwsza cyfra to 8, więc wyrzuć ją - odpowiedź będzie taka sama jak 675 do 689, a ponownie od 75 do 89.
Średnia waga pierwszych dwóch cyfr 86 wynosi 7, więc pozostałe cyfry wymagają średniej masy większej niż 7, aby się zakwalifikować. Tak więc połączenie
jest równa
Tak więc nasz zakres (nowej) pierwszej cyfry wynosi od 7 do 8, z następującymi możliwościami:
Dla 7 nadal potrzebujemy średnio więcej niż 7, co może pochodzić tylko z ostatniej cyfry 8 lub 9, co daje nam 2 możliwe wartości.
Dla 8 potrzebujemy średnio więcej niż 6, które mogą pochodzić tylko z ostatniej cyfry 7-9, co daje nam 3 możliwe wartości.
Zatem 2 + 3 daje 5 możliwych wartości.
Dzieje się tak, ponieważ algorytm zaczyna się od 4-cyfrowej liczby i dzieli ją na mniejsze problemy. Funkcja wywoływałaby się wielokrotnie z łatwiejszymi wersjami problemu, dopóki nie będzie w stanie poradzić sobie z tym problemem.
źródło
Może możesz pominąć wielu kandydatów w przedziale od a do b, kumulując ich „ciężkość”.
jeśli znasz długość swojego numeru, wiesz, że każda cyfra może zmienić ciężar tylko o 1 / długość.
Tak więc, jeśli zaczniesz od jednej liczby, która nie jest ciężka, powinieneś być w stanie obliczyć następną liczbę, która będzie ciężka, jeśli zwiększysz ją o jedną.
W powyższym przykładzie zaczynającym się od 8680 śr. = 5,5, czyli 7-5,5 = 1,5 punktu od granicy ciężkości, będziesz wiedział, że pomiędzy nimi jest 1,5 / (1/4) = 6 liczb, które NIE są ciężkie.
To powinno wystarczyć!
źródło
/length
.A może prosta funkcja rekurencyjna? Dla uproszczenia oblicza wszystkie ciężkie liczby z
digits
cyframi i minimalną sumę cyfrmin_sum
.Zaimplementowano to w pythonie i znaleziono wszystkie 9-cyfrowe ciężkie liczby w ~ 2 sekund. Trochę dynamicznego programowania może to poprawić.
źródło
To jedno z możliwych rozwiązań.
źródło
C, dla przedziału [a, b] jest to O (ba)
//ćwiczenie
//wyniki
źródło