โจทย์ข้อนี้เป็นแนว Math ซึ่งสามารถทำได้ วิธี
วิธีที่ 1 Brute Force
เริ่มจากการสังเกตว่าตัวเลขที่นำมาตรวจสอบนั้นค่าสูงสุดคือ จะเห็นว่าค่ามากที่สุดที่สามารถทำให้ คือ โดยค่าที่มากกว่า เมื่อยกกำลัง แล้วจะมากกว่า เสมอ
ดังนั้นเราจะหาจำนวนเต็มบวก ที่ทำให้ โดยตรวจสอบคู่ (a, b) ทั้งหมดที่เป็นไปได้ เริ่มตั้งแต่ และ เมื่อถึงค่า ที่ทำให้ มากกว่า จะไม่พิจารณาค่า ที่มากกว่านั้น แล้วพิจารณาค่า ถัดไป
คำตอบคือค่า ค่าแรก (ถ้าเราไล่ค่า จากน้อยไปมาก) ที่ทำให้ ที่เรารู้ว่าคำตอบคือค่าแรก ตัวอย่างเช่น ซึ่งมีคำตอบที่เป็นไปได้ได้แก่ สังเกตว่ายิ่งฐานเลขยกกำลังมาก เลขชี้กำลังจะน้อยลง ดังนั้นการไล่ค่า จากน้อยไปมาก จะทำให้เราได้คำตอบ ซึ่งมีค่ามากที่สุดเสมอ
วิธีสามารถทำได้เนื่องจากถ้าเราพิจารณา ซึ่งทันใน 1 วินาที
วิธีที่ 2 Number Theory
เนื่องจากจำนวนเต็มบวก ใดๆ สามารถเขียนในรูปผลคูณของจำนวนเฉพาะได้เสมอหรือก็คือ
โดย คือจำนวนเต็มที่ไม่ติดลบและ เป็นจำนวนเฉพาะที่ไม่ซ้ำกัน
สังเกตว่าถ้าเราเลือกจำนวนเฉพาะที่มากกว่า สองตัวใดๆคูณกันจะมากกว่า เสมอดังนั้นตัวเลขที่โจทย์ถามนั้นจะมี แบบ
- เป็นจำนวนเฉพาะ
- เป็นจำนวนประกอบที่มีตัวประกอบเฉพาะที่มากกว่า เพียงตัวเดียว
- เป็นจำนวนประกอบที่มีตัวประกอบเฉพาะทั้งหมดน้อยกว่าหรือเท่ากับ
ซึ่งแบบที่ และ จะไม่สามารถจัดให้อยู่ในรูป ที่ ได้ ดังนั้นเราจะหาจำนวนเฉพาะทั้งหมดที่น้อยกว่าหรือเท่ากับ โดยใช้ Sieve of Eratosthenes แล้วแยกตัวประกอบ ให้อยู่ในรูปของ
ถ้าเราแยกตัวประกอบให้อยู่ในรูปข้างต้นแล้ว ไม่เท่ากับ แปลว่าตัวเลขนี้มีจำนวนเฉพาะที่มากกว่า เป็นตัวประกอบ แล้วคำตอบของคำถามก็คือ ถ้าเท่ากับ ก็หมายความว่าตัวเลขนั้นไม่สามารถจัดให้อยู่ในรูป ที่ ได้เช่นกัน
ที่เราบอกว่าคำตอบคือ GCD ตัวอย่างเช่น เราจะสามารถแยกตัวประกอบได้เป็น จะเห็นว่า ซึ่งเราไม่สามารถจัดรูปให้ มีค่ามากกว่านี้ได้แล้ว โดยสังเกตว่า
ในขั้นตอนการหา GCD นั้นอาจเขียน Euclidean Algorithm หรือใช้ Built-in Function อย่าง __gcd (ใน C++) ก็ได้
Solution Code 1
#include <bits/stdc++.h> using namespace std; const int bound = 10000; int main() { int n; scanf("%d", &n); while (n--) { long long y; bool found = false; scanf("%lld", &y); for (int i = 2; i <= bound; i++) { long long now = i * i, power = i; for (int j = 2; j <= 32; j++) { if (now == y) { printf("%d\n", j); found = true; break; } now *= power; } if (found) { break; } } if (!found) { printf("NO\n"); } } }
Time Complexity
Solution Code 2
#include <bits/stdc++.h> using namespace std; const int MXN = 1e4 + 1; vector<bool> notprime(MXN, false); vector<int> prime; void sieve() { for (int i = 2; i < MXN; i++) { if (notprime[i]) { continue; } prime.emplace_back(i); for (int j = i * 2; j < MXN; j += i) { notprime[j] = 1; } } } int main() { int n; scanf("%d", &n); sieve(); while (n--) { int y, ans = -1; scanf("%d", &y); for (auto i : prime) { if (y % i == 0) { int now = 0; while (y % i == 0) { now++; y /= i; } if (ans == -1) { ans = now; } else { ans = __gcd(ans, now); } } } if (y != 1 || ans == 1) { printf("NO\n"); } else { printf("%d\n", ans); } } }
Time Complexity