[Problem]

Bài 1: Cho số tự nhiên A. Hãy tìm số tự nhiên N nhỏ nhất sao cho N lũy thừa N (nhân N cho chính nó N lần) chia hết cho A. Hãy viết chương trình tìm số N đó và xuất ra màn hình. Trong đó A có giá trị: 1 ≤ A ≤ 10^9.
Ví dụ:
Số nhập vào là A          Số xuất ra là N
8                                       4
13                                     13

[Solution]

Lần đầu tiên nhìn vào bài toán, nhiều bạn có thể tròn mắt nói rằng: số gì mà lớn vậy kiểu nào chứa nổi trời? Đúng thật, nếu nhìn ban đầu thì có lẽ chúng ta phải bó tay trước bài toán này. Nhưng nếu biết khóe léo vận dụng vài kiến thức của số học + vài nhận xét thì bạn có thể giải bài toán một cách nhẹ nhàng.
Trước hết quan sát trằng để N^N chia hết cho A, thì N phải chia hết cho các ước nguyên tố của A.
Mặt khác, nếu viết:
A= pr[1]^e[1]  *  pr[2]^e[2]  *  …  *  pr[k]^e[k];
Như vậy, với mỗi pr[.] cần xuất hiện ít nhất một lần trong N, nghĩa là N= pr[1]^t1 * pr[2]^t2 * … * pr[k]^tk, với ti>=1

Bước 1: Phân tích A ra tích các thừa số nguyên tố và số mũ của nó. Việc này có thể thực hiện nhanh chóng bằng sàng Eratosthenes, lưu ý các bạn không nên cài 1 hàm kiểm tra số nguyên tố và kiểm tra từng số nguyên tố từ 2 tới round(sqrt(A)) như vậy sẽ rất mất thời gian!

Bước 2: Ta xét các trường hợp cụ thể sau:
Trường Hợp 1 – A chỉ có 1 ước số nguyên tố:
Lúc này A=pr[1]^e[1], cần tìm N= pr[1]^x;
x sẽ chạy giá trị từ 1 tới ceil(e[1] / pr[1]) Cho đến khi x*pr[1]^x >= e[1] thì dừng, Lúc này N= pr[1]^x;

Trường Hợp 2 – A chỉ có 2 ước số nguyên tố:
Ta dùng 2 vòng lặp for lồng nhau để tìm ra N

kq = n;

for (int t1 = 1, temp1 = pr[1]; t1 <= e[1]; ++t1, temp1 *= pr[1])

for (int t2 = 1, temp = temp1 * pr[2]; t2 <= e[2]; ++t2, temp *= pr[2])

if (temp * t1 >= e[1] && temp * t2 >= e[2])

if (temp < kq) kq = temp;

Trường Hợp 3 – A có từ 3 ước nguyên tố trở lên:
Ta có 1 số nhận xét sau:
Do A <= 10^9 < 2^30 do đó khi N có 3 ước nguyên tố trở lên N >= pr[1]*pr[2]*pr[3] >= 2*3*5=30
mà với giới hạn đó thì số mũ tối đa của một cơ số (cụ thể là 2) không thể vượt quả 30. Vì vậy trong trường hợp này, giả dụ A có k ước nguyên tố N = pr[1] * pr[2] * … * pr[k].
Đến đây bài toán đã được giải quyết xong! 🙂
Bonus: Nói vậy thôi, bài này chủ yếu là dựa vào Google + chịu khó đọc hiểu bài giải có sẵn là có thể làm được, hihi :D!

[Code]

#include <stdio.h>
#include <string.h>
#include <conio.h>

#define lim 50000

bool
a[lim];
int
pr[lim/2], e[lim/2];

void SanNgTo(void)
{

memset(a,true,sizeof(a));

int i,j;
i = 1;
a[1]=false;

while (i*i<=lim){
while
(!a[i]) i++;

j=2;
while
(j*i<=lim){

a[j*i]=false;
j++;
}

i++;
}
}

void PhanTich(int n, int& k)
{

int
i=1;

k=0;
while
(n!=1){
while
(!a[i]) i++;

if (n%i==0){
k++;
pr[k]=i;

e[k]=0;
}

while
(n%i==0){

e[k]++;
n/=i;
}

i++;
}
}

int
Solve(int k, int n)
{

int kq;
switch
(k){
case
1:

int t;
t=e[1]/pr[1];

if (e[1]%pr[1]!=0) t++;

kq=1;
for
(int i=1; i<=t; i++)
{

kq*=pr[1];

if (kq*i>=e[1]) break;
}

break
;

case 2:
int
temp1, temp;
kq = n;

for (int t1 = 1, temp1 = pr[1]; t1 <= e[1]; ++t1, temp1 *= pr[1])

for (int t2 = 1, temp = temp1 * pr[2]; t2 <= e[2]; ++t2, temp *= pr[2])

if (temp * t1 >= e[1] && temp * t2 >= e[2])
if
(temp < kq) kq = temp;
break
;

default:
kq=1;
for
(int i=1;i<=k;i++)
kq*=pr[i];
}

return kq;
}

int
main(void)
{

SanNgTo();

int n, a, k=1;
printf(“Nhap A= “);

scanf(“%d”,&a);
PhanTich(a,k);
n = Solve(k,a);

printf(“So N nho nhat can tim: %d\n”,n);
printf(“va %d^%d chia het cho %d\n”,n,n,a);

getch();
}

Download Source Code (*.CPP)

Advertisements