• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Silnia zapisana tekstowo

Object Storage Arubacloud
+1 głos
469 wizyt
pytanie zadane 26 kwietnia 2023 w C i C++ przez polandonion Mądrala (7,040 p.)
Witam, mam sprawdzić, czy podana na wejściu liczba n (1 <= n <= 10 ^ (10 ^ 5)) jest silnią liczby naturalnej (np. 720 - TAK (6!), 120 - TAK (5!), 121 - NIE).

Na początku zamierzałem zrobić funkcję mnożącą liczby zapisame tekstowo i zaczynałbym od jedynki, potem razy 2, potem razy 3 itd... i robułbym to dopóki aktualny wynik nie jest krótszy od wejściowego, a jak długości bedą takie same, to porównuję dwa teksty.

Zapytałem nauczyciela i powiedział mi, że prędzej się zapiszę na śmierć, ale jednocześnie dał mi wskazówkę, a mianowicie powiedział, żebym skorzystał z arytmetyki modularnej, ale do tej pory nie wiem jak to zrobić. Pomożecie?

5 odpowiedzi

+1 głos
odpowiedź 27 kwietnia 2023 przez Whistleroosh Maniak (56,980 p.)

Mam ciekawy pomysł heurystyczny.

Powiedzmy, że n to liczba której silnia jest na wejściu. Wtedy n jest ograniczone przez 26000 (można sprawdzić pythonem). Znajdźmy ile dokładnie wynosi to n. Można to pewnie zrobić korzystając z jakichś oszacowań silni albo zliczając zera.

Wybierzmy k liczb pierwszych większych od 26000, nazwijmy je p_1, p_2, ..., p_k. Policzmy n! mod p_1, n! mod p_2, ... Tak samo policzmy resztę z dzielenie przez kolejno p_1, p_2, ... dla liczby z wejścia. Porównajmy czy otrzymane reszty dla p_1, p_2, ... są takie same w obu przypadkach. Jak nie są to liczba z wejścia nie jest silnią. Jeśli są to jest jakieś prawdopodobieństwo, że rzeczywiście liczba z wejścia jest silnią liczby n. Pytanie tylko jak duże jest to prawdopodobieństwo. Niestety nie jestem w stanie tego oszacować, więc zostaje to zaimplementować i zobaczyć czy działa.

komentarz 28 kwietnia 2023 przez pasjonat_algorytmiki Pasjonat (19,540 p.)
a modulo jakie najlepiej ustawić? Bo wsumie to wygląda jakby miało duży sens.
komentarz 28 kwietnia 2023 przez Whistleroosh Maniak (56,980 p.)
Najlepiej jakaś losowa duża liczba pierwsza
+1 głos
odpowiedź 12 maja 2023 przez polandonion Mądrala (7,040 p.)
edycja 12 maja 2023 przez polandonion

no wiec ok, znalazlem juz sposob, ktory daje 100% i nie jest taki truny do napisania, a raczej do wymyslenia:

  • wczytaj liczbe na wejsciu jako string,
  • oblicz wartosc tej liczby modulo jakas duza liczba pierwsza,
  • rozpoczynam symulacje:
    • liczba na poczatku jest rowna 1,
    • potem mnoze ja przez 2, 3, 4, 5, ... nie zapominajac, ze przy kazdym mnozeniu musze zmodulowac ta liczbe przez to samo modulo, przez ktore zmodulowalem wejsciowego stringa,
    • ide while'm dopoki liczby te nie sa rowne.

Tutaj kod w C++:

#include <iostream>
#include <string>

using namespace std;

int main() {
	string str;
	cin >> str;

	int q = 694202137; // liczba pierwsza, latwa do zapamietania
	long long str_int = 0;

	for (char c : str)
		str_int = (str_int + (long long)(c - '0')) % q * 10;
	str_int /= 10;

	long long sil = 1, i = 1;

	while (sil != str_int and i < 30000)
		sil = (sil * ++ i) % q;

	if (sil == str_int)
		cout << i;
	else
		cout << "TO NIE SILNIA!";
	
}

Calosc dziala bez zarzutu w znakomitym czasie.

1
komentarz 12 maja 2023 przez Whistleroosh Maniak (56,980 p.)
Ciekawe, wygląda na prostszą wersję mojego pomysłu. Tylko ja mnożyłem przez wiele liczb pierwszych, bo zgodnie z chińskim twierdzeniem o resztach istnieje wiele liczb, które dadzą ten sam wynik modulo pewne liczby pierwsze. Wiec teoretycznie da się ułożyć test, który wywali się dla nie dużych liczb pierwszych.
1
komentarz 12 maja 2023 przez Whistleroosh Maniak (56,980 p.)

Dla takiego testu nie zadziała:

491744029
0 głosów
odpowiedź 27 kwietnia 2023 przez Great Stary wyjadacz (12,360 p.)

Opisana metoda jest poprawna i stosunkowo prosta w implementacji. Chociaż niekoniecznie jest szybka. Do zapisu dużych liczb, których nie pomieszczą standardowe typy arytmetyczne może zostać użyta: tablica, string, vector, deque itd. Przykładowy algorytm realizujący mnożenie mógłby wyglądać tak:

#include <iostream>
#include <deque>

void multiply(int value, std::deque<int>& result) {
	int carry = 0;
	for (int i = result.size() - 1; i >= 0 ; --i) {
		int prod = result[i] * value + carry;
		result[i] = prod % 10;
		carry = prod / 10;
	}

	while (carry) {
		result.emplace_front(carry % 10);
		carry /= 10;
	}
}

int main() {
	std::deque<int> num{7, 2, 0};
	multiply(7, num);
	std::cout << "6! * 7 =\n720 * 7 =\n";
	for (int i : num) {
		std::cout << i;
	}
}
komentarz 27 kwietnia 2023 przez polandonion Mądrala (7,040 p.)
no ok, ale co z liczbami niepoprawnymi, tzn tymi, ktore nie sa silniami. Taki przypadek tez musze obslugiwac
komentarz 27 kwietnia 2023 przez Great Stary wyjadacz (12,360 p.)
edycja 27 kwietnia 2023 przez Great

Na początku zamierzałem zrobić funkcję mnożącą liczby zapisame tekstowo i zaczynałbym od jedynki, potem razy 2, potem razy 3 itd... i robułbym to dopóki aktualny wynik nie jest krótszy od wejściowego, a jak długości bedą takie same, to porównuję dwa teksty.

Liczba nie będzie silnią w sytuacji, gdy "aktualny wynik" (zawierający n-tą poprawną wartość silni) jest dłuższy od reprezentacji ciągu cyfr liczby sprawdzanej. Liczba jest silnią, gdy porównane ciągi tej samej długości są takie same.

0 głosów
odpowiedź 27 kwietnia 2023 przez pangozdzik Nowicjusz (140 p.)

Coś w ten deseń?

Kod jest brzydki, ale oddaje esencję tematu. Chyba..

Pozdrawiam!

#include <iostream>
using namespace std;

double dzielnik;
int licznik=1;

int main() 
{
    cout<<"Jeśli 1 to będzie silnia! Jest: ";
    dzielnik=720;  //tutaj można dać cin
while(dzielnik>1)
{
 dzielnik=dzielnik/licznik;
 licznik++;
}
cout<<dzielnik<<endl;
if(dzielnik==1)  // if do zmodyfikowania, by wyświetlał 'TAK/NIE'
cout<<"Silnia z liczby: "<<licznik-1<<endl;
return 0;
}

 

komentarz 27 kwietnia 2023 przez pangozdzik Nowicjusz (140 p.)
...a z tą arytmetyką, to chodzi chyba o %, modulo -> dzielenie z resztą.
komentarz 27 kwietnia 2023 przez Great Stary wyjadacz (12,360 p.)
Ten program nie będzie działać dla podanego przez autora zakresu (1 <= n <= 10 ^ (10 ^ 5)). Przykładowo 20! to nie jest 2432902008176640001.
komentarz 27 kwietnia 2023 przez pangozdzik Nowicjusz (140 p.)
Dzięki. Wracam do nauki :)
0 głosów
odpowiedź 27 kwietnia 2023 przez pasjonat_algorytmiki Pasjonat (19,540 p.)
edycja 27 kwietnia 2023 przez pasjonat_algorytmiki
Ale jaki problem bo nie rozumiem. Robisz dokładnie to samo co pisałes na początku trzymasz tekst jako stringa i mnożysz pisemnie przez kolejne liczby. Jak spotkasz że długość tego co mnożysz jest == długość wejściu, to sprawdzasz czy pasuje, jak mniejsza to mnożysz dalej, a jak większa to kończysz. Nie rozumiem o co chodzi z zakopaniem się na śmierć.
komentarz 27 kwietnia 2023 przez pasjonat_algorytmiki Pasjonat (19,540 p.)
Jedynie czasowo może nie przejść
komentarz 27 kwietnia 2023 przez polandonion Mądrala (7,040 p.)
no a właśnie jest jakiś taki szybszy sposób na to zadanie niż pisanie własnej funkcji mnożącej?
komentarz 27 kwietnia 2023 przez polandonion Mądrala (7,040 p.)

no bo takie casy dostaje, jak robie wlasnie tym sposobem, co pisalem, ze nie jestem pewien czy przejdzie:

komentarz 27 kwietnia 2023 przez pasjonat_algorytmiki Pasjonat (19,540 p.)
skoro Ci nauczyciel powiedział, że jest z arytmetyką modularną, to pewnie jest. Ja nie jestem dobry z arytmetyki modularnej i nwm jak to zrobić szybciej.

Podobne pytania

0 głosów
0 odpowiedzi 1,991 wizyt
pytanie zadane 6 marca 2022 w C i C++ przez drogakola Nowicjusz (120 p.)
0 głosów
1 odpowiedź 141 wizyt
pytanie zadane 28 kwietnia 2021 w C i C++ przez ndel07 Nowicjusz (180 p.)
+1 głos
1 odpowiedź 114 wizyt
pytanie zadane 17 stycznia 2021 w C# przez ppb434 Nowicjusz (170 p.)

92,579 zapytań

141,432 odpowiedzi

319,664 komentarzy

61,964 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...