Tải bản đầy đủ (.doc) (8 trang)

Bài toán số nguyên tố tối ưu

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (127.52 KB, 8 trang )

Tối ưu các bài toán về số nguyên tố
Đinh Hữu Công
Trong số 11-2001 tácgiả Nguyễn Văn Trường đã giới thiệu các thuật toán về số nguyên
tố.Nhưng một số thuật toán này còn bị hạn chế về thời gian và bộ nhớvới n lớn. Tuỳ vào
từng bài toán cụ thể ta có thể tối ưu hoá nhữngthuật toán này dựa vào những nhận xét và
chứng minh toán học.
Bài toán 1: Cho số tựnhiên n. Hãy phân tích số n thành tích các thừa số nguyên tố
Input: file Phantich.inp với số n duy nhất (n < 2
31
)
Ouput: file Phantich.out. Dòng 1 là k, số thừa số nguyên tố khác nhautrong phân tích. K
dòng tiếp theo dòng thứ i gồm 1 cặp số (p,q) cáchnhau 1 dấu trắng trong đó p là thừa số
nguyên tố và q là số mũ tươngứng của nó trong phân tích (q > 0).
Thuật toán của bài này rất đơn giản:
+ Cho biến chạy Temp=0,
+ Lặp: Chừng nào temp≤n thì làm
- Temp:=số nguyên tố liền sau Temp;
- While (n mod Temp=0) do
Begin
n:=n div Temp;
Tăng số mũ của Temp;
End;
Hiệuquả của cài đặt chủ yếu phụ thuộc vào công đoạn tìm số nguyên tốliền sau Temp.
Cách nhanh nhất là dùng 1 mảng để lưu trữ các số nguyêntố từ 1 đến n. Với n=1 tỷ ta phải
lưu (10
9
) = 50.847.534 số nguyên tố nên ta không thể có đủ bộnhớ để thực hiện điều này.
Một cách khác là ta tuần tự tăng biếnTemp và kiểm tra Temp có nguyên tố không, cách
này không tốn bộ nhớnhưng không khả thi vì thời gian thực hiện quá lâu. Một cách tự
nhiên,ta muốn dung hoà cả hai phương pháp trên. Vì vậy ta sẽ tìm cách giảmkhối lượng
lưu trữ và số lần kiểm tra nguyên tố:


Bước 1: Kiểm tra n. Nếu n nguyên tố hoặc n=1thìvấn đề trở nên quá đơn giản. Nếu n là
hợp số thì chuyển sang bước2.
Bước 2: Vì n là hợp số nên ta phải có n=a*b(1<a ≤ b) suy ra a ≤ sqrt(n)≤ 2
15,5
< 1. Vậy ta
chỉ cần lưu các số nguyên tố nhỏ hơn 6341
Vìn< 2
31
nên số thừa số nguyên tố nhỏ hơn 10 (2*3*5*..31 >2
31
), do đó ta chỉ phải kiểm tra
nguyên tố khoảng 10 lần
Chươngtrình của bài này như sau:
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+}
{$M65500,0,655360}
{Phantich so n<2^31 thanh thua so nguyen to}
usescrt;
constmaxPrime=46341; {max Prime = }
Fin=′phantich.inp′;
Fou=′phantich.out′;
var p:array[1..10] of longint;
q:array[1..10] of integer; { Số thừa số nguyên tố lớn nhất là 10?}
Prime:array[0..maxPrime+1] of boolean;
n:longint;
count:integer;
temp:word;
f,g:text;
procedureEratosten;
vari,j:word;
begin

Fillchar(Prime,sizeof(Prime),true);
Prime[0]:=false;
Prime[1]:=false;
for i:=2 to trunc(sqrt(maxPrime)) do
if Prime[i] then
for j:=2 to (maxPrime div i) do
Prime[i*j]:=false;
end;
functionisPrime(n:longint):boolean;
vari,step:word;
begin
isPrime:=false;
if (n
begin
if Prime[n] then isPrime:=true;
exit;
end;
if ((n mod 2=0) or (n mod 3=0)) then Exit;
i:=5;
step:=2;
while (i≤sqrt(n)) do
begin
if (n mod i=0) then
exit;
i:=i+step;
step:=6-step;
end;
isPrime:=true;
end;
procedureSolve;

begin
Assign(f,Fin);
Reset(f);
Readln(f,n);
Close(f);
Assign(g,Fou);
Rewrite(g);
if n<2 then
begin
writeln(g,0);
Close(g);
Halt;
end;
temp:=2;
count:=0;
Fillchar(p,sizeof(p),0);
Fillchar(q,sizeof(q),0);
while (n<>1) do
begin
if isPrime(n) then
begin
Inc(count);
p[count]:=n;
q[count]:=1;
exit;
end
else
begin
while ((n mod temp<>0) and (temp< i>
begin

Inc(temp);
while not Prime[temp] do
Inc(temp);
end;
Inc(count);
p[count]:=temp;
while (n mod temp=0) do
begin
Inc(q[count]);
n:=n div temp;
end;
end;
end;
end;
procedureResult;
vari:integer;
begin
Writeln(g,count);
for i:=1 to count do
Writeln(g,p[i],' ',q[i]);
Close(g);
end;
BEGIN
Eratosten;
Solve;
Result;
END.
Saukhi làm bài toán 1 ta sẽ dễ dàng làm được bài toán số 2 trong đềkhối 10 cuộc thi
Olympic 30-4 lần VIII.
Đề bài như sau:

Cho số nguyên dương n (1 < n < 2
31
). Tìm số nguyêndương a nhỏ nhất sao cho a
a
chia hết
cho n.
Input: file Chiahet.inpchứa 1 số duy nhất n
Output: file Chiahet.out chứa số a
Bàitoán 2: Tìm số mũ của số nguyên tố p trong cách phân tích của n! ra thừa sốnguyên tố
(n ≤ 2
31
)
Cũng như bài toán 1, việc duyệt các số nguyên là bội của p từ1 đến n để chia cho p tìm số
mũ rồi lấy tổng các số mũ này là khôngthể thực hiên được.
Ví dụ:
Nếun=2
31
còn p = 2 thì ta phải duyệt qua (n div p) số, đại lượngnày bằng 2
30
=1.073.741.824 tức là hơn 1 tỷ số cần phải duyệt.Nội chỉ việc cho biến i chạy qua 2
30
số
này mà chưa làm gìcả cũng đã mất khoảng 10 giây rồi (nếu không tin bạn hãy viết
chươngtrình chỉ gồm 1 lệnh cho i chạy từ 1 đến 1 tỉ không làm gì cả vàviết hàm đếm thời
gian xem).
Như vậy ta cần phải tìm 1 cách khác để tính số mũ của p. Gọis
i
là số số chia hết cho p
i
trong khoảng 1..n. Số này bằng tổng của số các số chia hết cho p, p

2
, p
3
…trong khoảng
1..n. Dễ thấy số mũ của p là s
1
+s
2
+…+s
k
với k lớn nhất sao cho p
k
≤ n
Vídụ: n=29 vàp =3 thì k=3, s
1
=9, s
2
=3, s
3
=1 → Số mũ của 3 là s
1
+s
2
+s
3
=13
Mặtkhác các số chia hết cho p
i
trong khoảng 1..n là: 1* p
i

, 2*p
i
, 3* p
i
, …,

* p
i
→ có
số. Đây chính là nội dung củađịnh lý Lơgiăngđrơ: Số mũ của số nguyên tố p trong
phân tích n!thành các thừa số nguyên tố là:
Đểý rằng (Số số chia hết cho p
i+1
trong khoảng 1..n bằng số số chia hết cho
p
i
trong khoảng 1..(ndiv p)). áp dụng điều này với i=1 ta có được chươngtrình hàm tính số
mũ của p trong phân tích ra thừa số nguyên tố củan!
functionSoMu(p:longint;n:longint):integer;
varcount:integer;
begin
count:=0;
while n<>0 do
begin
n:=n div p;
Count:=count + n;
end;
SoMu:=count;
end;
Vớik đủ lớn ta có hay n < p

k
. Vì vậy hàm SoMu chỉ phải vào vòng lặp k lầnvới k là
số nguyên nhỏ nhất sao cho n < p
k

Cụthể trong bài này trường hợp lớn nhất là n = 2
31
; p = 2 thì
k = log
2
2
31
= 31 so với 2
30
(nhỏ hơn34 triệu lần) !
Bài toán 3: Tìm số chữ số 0 tận cùng và chữ số tận cùng khác 0 của n! (n< 2
31
). Dữ liệu
nhập từ bàn phím số n và in kết quả sốchữ số 0 tận cùng và chữ số tận cùng khác 0 của n!
ra màn hình
Cơsở thuật toán: Ta thấy n! khi phân tích ra thừa số nguyên tố thìcó dạng
n! = 2
SoMu(2,n)
* 5
SoMu(5,n)
*…
Trong công thức Lơgiăngđrơ nếu p
1
< p
2

thìSoMu(p
1
,n) ≥ SoMu(p
2
,n) nên số chữ số 0 tận
cùng của n! chính làSoMu(5,n).
Đặt m = SoMu(2,n) - SoMu(5,n).Bỏ đi các chữ số 0 tận cùng thì ta có: Chữ số tận cùng
khác 0 cua n! = [(2
m
mod 10) *TanCung(n)] mod 10 với TanCung(n) là chữ số tận cùng của
n! đã bỏ đihết số mũ của 2 và 5. Dễ thấy 2
m
mod 10 chỉ phụ thuộc vào(m mod 4), nếu m
mod 4 = 0, 1, 2, 3 thì 2
m
mod 10 = 6, 2, 4, 8 (trừtrường hợp m = 0). Công việc còn lại là tìm
hàm TanCung(n) (Nếu bâygiờ chỉ nói tận cùng thì ta hiểu là số đó đã được chia cho 2 và5
đến dư).
Ví dụ: Tận cùng của 10 là 1, của 14 là 7 …
Nếun tương đối nhỏ thì ta có thể duyệt bằng 1 vòng for để tìm tận cùngcủa n!. Nhưng n có
thể lên tới 2 tỷ nên ta xây dựng hàm TanCung(n) nhưsau (với ví dụ n = 27):
Nếu n < 10 thì duyệt bình thường. Xét n ≥10, ta tính tận cùng của tích (n mod 10) số
liêntiếp từ * 10 + 1 đến n
(temp=21*22*23*24*25*26*27=21*11*23*3*1*13*27=1*1*3*3*1*3*7=9)
temp:=1;
fori:=n+1-n mod 10 to n do
begin
tg:=i;
while not ođ(tg) do
tg:=tg shr 1;

while (tg mod 5=0) do
tg:=tg div 5;
temp:=temp*(tg mod 10) mod 10;
end;
temp:=temp mod 10;

×