Solution
วิธีทำข้อนี้คือให้สร้าง Array ที่มีขนาด ช่อง โดยแต่ละช่องจะมีค่า กับ เท่านั้น (ถ้า Array ช่องที่ มีค่าเท่ากับ แปลว่าเลข ยังไม่ถูกขีดฆ่า แต่ถ้าเป็น แปลว่าถูกขีดฆ่าแล้ว)
ให้ คือเลขที่นับว่าขีดฆ่าไปแล้วกี่ครั้ง และ หมายถึงตัวเลขน้อยสุดที่ยังไม่ถูกขีดฆ่า
เนื่องจากจำนวนที่น้อยที่สุดที่ยังไม่ถูกขีดฆ่าต้องเป็นจำนวนเฉพาะอยู่แล้ว เพราะหลังจากขีดฆ่าไป จำนวนที่ไม่ใช่จำนวนเฉพาะที่มาก่อนจำนวนน้อยที่สุดที่ยังไม่ถูกขีดฆ่า ก็จะถูกขีดฆ่าไป เช่น , , , , , หลังจากเริ่มขีดฆ่าพหุคูณของ จะเหลือเลข , , , ขีดฆ่าพหุคูณของ จะเหลือ , ขีดฆ่าพหุคูณของ จะเหลือเลข เป็นตัวสุดท้าย จะเห็นได้ว่าจำนวนที่น้อยที่สุดที่ยังไม่ถูกขีดฆ่า จะเป็นจำนวนเฉพาะเสมอ ดังนั้นไม่ต้องสนใจประโยคที่ว่า "ให้จำนวนนั้นคือ ( คือจำนวนเฉพาะ )"
ขั้นตอนการทำงาน
- ถ้า Array ช่องที่ มีค่าเท่ากับ ให้ข้ามไปทำขั้นตอนที่ 6
- ไล่จำนวนที่เป็นพหุคูณของ ที่น้อยกว่าหรือเท่ากับ และให้เลขนั้นคือเลข แล้วทำขั้นตอนที่ 2 ถึง 4 ให้ครบทุกตัว
- ถ้า Array ช่องที่ มีค่าเท่ากับ ให้ มีค่าเพิ่มขึ้นเป็นเป็นพหุคูณของ ตัวถัดไป
- ให้ มีค่าเพิ่มขึ้น และ กำหนดให้ค่าของ Array ช่องที่ มีค่าเท่ากับ
- ถ้า มีค่าเท่ากับ ให้ส่งออกค่า แล้วจบการทำงาน
- เพิ่มค่า ให้มากขึ้น แล้วกลับไปทำขั้นตอนที่ 1
ตัวอย่างการทำงานของ (ค่าในตารางแสดงถึงลำดับที่ถูกขีดฆ่า)
รอบที่\เลข | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|
1 | 1 | 0 | 2 | 0 | 3 | 0 |
2 | 1 | 4 | 2 | 0 | 3 | 0 |
3 | 1 | 4 | 2 | 5 | 3 | 0 |
4 | 1 | 4 | 2 | 5 | 3 | 7 |
Code
#include <iostream> #include <vector> using namespace std; int main() { int n, k; cin >> n >> k; vector<int> alr(n+1); int c = 0, j = 2; while (1) { if (!alr[j]) { for (int i = j; i <= n; i += j) { if (!alr[i]) { c++; alr[i] = 1; if (c == k) { cout << i; return 0; } } } } j++; } return 0; }