Reseto

0018

Solution

วิธีทำข้อนี้คือให้สร้าง Array ที่มีขนาด N+1N+1 ช่อง โดยแต่ละช่องจะมีค่า 00 กับ 11 เท่านั้น (ถ้า Array ช่องที่ xx มีค่าเท่ากับ 00 แปลว่าเลข xx ยังไม่ถูกขีดฆ่า แต่ถ้าเป็น 11 แปลว่าถูกขีดฆ่าแล้ว)

ให้ cc คือเลขที่นับว่าขีดฆ่าไปแล้วกี่ครั้ง และ jj หมายถึงตัวเลขน้อยสุดที่ยังไม่ถูกขีดฆ่า

เนื่องจากจำนวนที่น้อยที่สุดที่ยังไม่ถูกขีดฆ่าต้องเป็นจำนวนเฉพาะอยู่แล้ว เพราะหลังจากขีดฆ่าไป จำนวนที่ไม่ใช่จำนวนเฉพาะที่มาก่อนจำนวนน้อยที่สุดที่ยังไม่ถูกขีดฆ่า ก็จะถูกขีดฆ่าไป เช่น 22, 33, 44, 55, 66, 77 หลังจากเริ่มขีดฆ่าพหุคูณของ 22 จะเหลือเลข 33, 55, 66, 77 ขีดฆ่าพหุคูณของ 33 จะเหลือ 55, 77 ขีดฆ่าพหุคูณของ 55 จะเหลือเลข 77 เป็นตัวสุดท้าย จะเห็นได้ว่าจำนวนที่น้อยที่สุดที่ยังไม่ถูกขีดฆ่า จะเป็นจำนวนเฉพาะเสมอ ดังนั้นไม่ต้องสนใจประโยคที่ว่า "ให้จำนวนนั้นคือ PP ( PP คือจำนวนเฉพาะ )"

ขั้นตอนการทำงาน

  1. ถ้า Array ช่องที่ jj มีค่าเท่ากับ 11 ให้ข้ามไปทำขั้นตอนที่ 6
  2. ไล่จำนวนที่เป็นพหุคูณของ jj ที่น้อยกว่าหรือเท่ากับ NN และให้เลขนั้นคือเลข ii แล้วทำขั้นตอนที่ 2 ถึง 4 ให้ครบทุกตัว
  3. ถ้า Array ช่องที่ ii มีค่าเท่ากับ 11 ให้ ii มีค่าเพิ่มขึ้นเป็นเป็นพหุคูณของ jj ตัวถัดไป
  4. ให้ cc มีค่าเพิ่มขึ้น 11 และ กำหนดให้ค่าของ Array ช่องที่ ii มีค่าเท่ากับ 11
  5. ถ้า cc มีค่าเท่ากับ KK ให้ส่งออกค่า ii แล้วจบการทำงาน
  6. เพิ่มค่า jj ให้มากขึ้น 11 แล้วกลับไปทำขั้นตอนที่ 1

ตัวอย่างการทำงานของ N=7N = 7 (ค่าในตารางแสดงถึงลำดับที่ถูกขีดฆ่า)

รอบที่\เลข234567
1102030
2142030
3142530
4142537

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;
}