Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified md/0011.md
100755 → 100644
Empty file.
1 change: 1 addition & 0 deletions md/1000.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi1_chain/solution)
24 changes: 1 addition & 23 deletions md/1001.md
Original file line number Diff line number Diff line change
@@ -1,23 +1 @@
กำหนดให้ $input[i][j]$ เป็น array สองมิติที่บ่งบอกถึงสถานะเริ่มต้นของเกม ซึ่งมาจากการแบ่งข้อมูลนำเข้าเป็นแต่ละ char แล้วนำใส่ char[][]

ในทางคล้ายๆกัน เราจะนิยาม $result[i][j]$ เป็น array สองมิติที่บ่งบอกทถึงสถานะตอนท้ายของเกมเมื่อโปรแกรมทำงานเสร็จ ฉนั้น $result$ จะเท่ากับ $input$ เมื่อโปรแกรมเริ่มทำงานแล้วเราจะเปลี่ยนแปลงค่าในนี้ให้กลายเป็นสถานะตอนท้ายของเกมในที่สุด

กำหนดให้ $free[i][j]$ เป็น array สองมิติที่บ่งบอกว่าในช่องที่ $(i, j)$ ของตารางเกมมีสิ่งกีดขวางหรือไม่ (รวมไปถึงก้อนอิฐที่อยู่ในตำแหน่งนั้นอยู่แล้ว)

Pseudocode ของอัลกอริทึมในการวางก้อนอิฐจะเป็นดังนี้:

```
for i in [1, n]:
for j in [1, m]:
result[i][j] = input[i][j]
free[i][j] = true

for j in [1, m]:
let i = 1
while i <= n and free[i][j]:
i += 1
free[i][j] = false
result[i][j] = '#'

print(result)
```
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi1_brick/solution)
137 changes: 1 addition & 136 deletions md/1002.md
Original file line number Diff line number Diff line change
@@ -1,136 +1 @@
### Original Solution

ข้อนี้อาจดูเหมือนจะมีเฉลยที่วุ่นวายมากๆ แต่ถ้าหากเราสามารถแบ่งกรณีได้อย่างเป็นระบบระเบียบก็จะไม่วุ่นวายมาก

สำหรับทุกจำนวนเต็มน้อยกว่าหรือเท่ากับ $d$ เราต้องการหาจำนวน i, v, x, l, c ที่ต้องใช้ สมมุติว่าเรากำลังพิจารณาตัวเลข $n$ อยู่

Pseudocode จะเป็นดังต่อไปนี้
```
while n >= 0:
if n >= 100:
c += 1
n -= 100
elif n >= 90:
c += 1
x += 1
n -= 90
elif n >= 50:
l += 1
n -= 50
elif n >= 40:
l += 1
x += 1
n -= 40
elif n >= 10:
x += 1
n -= 10
elif n >= 9:
x += 1
i += 1
n -= 9
elif n >= 5:
v += 1
n -= 5
elif n >= 4:
v += 1
i += 1
n -= 4
else:
i += 1
n -= 1
```

สังเกตุว่าในแต่ละรอบของ while loop $n$ จะเข้าเพียงหนึ่งกรณีเท่านั้น และอัลกอริทึมจะพิจารณากรณีที่ $n$ มากๆไปหา $n$ น้อยๆเสมอเพื่อรับประกันว่าสัญลักษณ์ที่มีค่ามากกว่าจะอยู่ทางซ้ายเสมอ (โดยมีข้อยกเว้นดังที่ระบุไว้ในตัวโจทย์)

### Alternative Solution

จริง ๆ ข้อนี้สามารถมองเหมือนเป็น pattern ได้เหมือนกัน ลองดูแบบนี้ครับ ลำดับของอักษรแทนเลขโรมัน คือ `I V X L C` ตามลำดับ

พิจารณาเลข `1, 2, 3, ..., 9`

```
1 : I
2 : II
3 : III
4 : IV
5 : V
6 : VI
7 : VII
8 : VIII
9 : IX
```

พิจารณา `10, 20, 30, ..., 90`

```
10 : X
20 : XX
30 : XXX
40 : XL
50 : L
60 : LX
70 : LXX
80 : LXXX
90 : XC
```

พิจารณา `100, 200, 300`

```
100 : C
200 : CC
300 : CCC
```

จะสังเกตได้ว่าเลขแบ่งเป็นชุดตัวอักษร ชุดละ 3 ตัว เรียกจากมากไปน้อยจะเป็น `I V X` ของ 1 - 9, `X L C` ของ 10 - 90, และ 100 - 300 ทั้งหมดเป็นไปตามกฎการเพิ่มแบบเดียวกัน ทั้งนี้เพื่อให้เหมือนกับ 2 ชุดก่อนหน้า เราสามารถสมมุติให้มีตัวอักษรอีก 2 ตัวเพิ่มขึ้นมาข้างหลังได้ `C _ _`

นอกจากนี้ ตัวเลขโรมันในแต่ละหลักจะต่อกันไปเรื่อยเลย เช่น `318` ก็คือ `300 (CCC) + 10 (X) + 8 (VIII) = CCCXVIII` ดังนั้น เราสามารถหาว่าแต่ละหลักเป็นเลขอะไร แล้วค่อย ๆ ไล่นับจำนวนตัวอักษร โดยเราจะสร้าง array มาเก็บจำนวนของแต่ละตัวอักษร เรียงจากน้อยไปมาก และบวกเพิ่มโดยใช้ array อีกตัวที่เก็บว่าเลขในหลักนั้น ๆ มีตัวอักษรตาม pattern ที่กล่าวไปข้างต้นอย่างไร

```cpp
#include <bits/stdc++.h>

using namespace std;

int factor[][3] = {
{0, 0, 0},
{1, 0, 0},
{2, 0, 0},
{3, 0, 0},
{1, 1, 0},
{0, 1, 0},
{1, 1, 0},
{2, 1, 0}, /// เช่น XII ถ้าเป็นหลักหน่วย และ LXX ถ้าเป็นหลักสิบ
{3, 1, 0},
{1, 0, 1}
};

int cnt[7]; /// [I, V, X, L, C, _, _]

/// เพิ่มค่าใน cnt โดย start_pos จะขึ้นอยู่กับว่าเป็นเลขในหลักใด
/// หลักหน่วย -- 0 เพื่อให้ไปบวกเพิ่ม ณ ตำแหน่ง [I, V, X]
/// หลักสิบ -- 2 เพื่อให้ไปบวกเพิ่ม ณ ตำแหน่ง [X, L, C]
/// หลักร้อย -- 4 เพื่อให้ไปบวกเพิ่ม ณ ตำแหน่ง [C, _, _]

void add(int start_pos, int num) {
for(int i = 0; i < 3; i++) {
cnt[start_pos + i] += factor[num][i];
}
}

int main() {
int d;
cin >> d;

for(int i = 1; i <= d; i++) {
add(0, i % 10); /// หลักหน่วย
add(2, (i / 10) % 10); /// หลักสิบ
add(4, i / 100); /// หลักร้อย
}

for (int i = 0; i < 5; i++) {
cout << cnt[i] << " ";
}

return 0;
}
```
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi1_roman/solution)
16 changes: 1 addition & 15 deletions md/1003.md
Original file line number Diff line number Diff line change
@@ -1,15 +1 @@
นิยาม $DP[i] = 1$ เมื่อ $i$ เป็น nugget number และ $DP[i] = 0$ เมื่อ $i$ ไม่ใช่ nugget number

Pseudocode ในการหา $DP$ จะเป็นดังต่อไปนี้
```
for i in [0, n]:
DP[i] = 0
DP[6] = DP[9] = DP[12] = 1
for i in [13, n]:
if DP[i-6] == 1 or DP[i-9] == 1 or DP[i-12] == 1:
DP[i] = 1
```

จากนี้เลข $i$ ใดๆที่ $DP[i] = 1$ คือ nugget number

ทั้งหมดนี้หาได้ในเวลา $O(n)$
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi1_nugget/solution)
4 changes: 1 addition & 3 deletions md/1004.md
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
ข้อนี้เป็นการจำลองสถานการณ์โดยใช้ queue เข้ามาช่วย เมื่อมีเด็กถูกเรียนกมาเข้าแถว เราก็จะใช้คำสั่ง push ของ queue และเมื่อต้องการนำนักเรียนที่อยู่หัวแถวออกจากแถว เราก็จะใช้คำสั่ง pop ของ queue

ใน C++ STL สามารถใช้ function ดังกล่าวโดยตรงจาก API ของ queue
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi1_plate/solution)
21 changes: 1 addition & 20 deletions md/1005.md
Original file line number Diff line number Diff line change
@@ -1,20 +1 @@
ปัญหาที่ตั้งขึ้นมาในข้อนี้เป็นหนึ่งใน classical problem หรือว่าได้ว่าเป็นปัญหาที่เจอได้บ่อยครั้ง คือปัญหา maximum sum subsequence ปัญหา maximum sum subsequence มีหลายวิธีที่สามารถจะแก้ได้โดยใช้เวลาเพียง $O(n)$ เท่านั้น เช่นเราอาจใช้ Kadane's algorithm หรือ deque มาแก้ก็ได้

อย่างไรก็ตาม เทคนิคเหล่านี้ยากเกินกว่าที่จะเหมาะสมกับโจทย์ในระดับ 10 เลยขออธิบายอัลกอริทึมที่ใช้เวลา $O(n^2)$ เนื่องจากโจทย์กำหนดว่า $n \leq 2500$ ดังนั้น $n^2 = 6250000$ ซึ่งยังสามารถทำงานเสร็จได้ภายในหนึ่งวินาทีสำหรับภาษา C/C++ แน่นอน

อัลกอริทึมที่ใช้ก็คำ for-loop สองชั้น โดยไล่ตัวแปร $i$ จาก $[0, n)$ และสำหรับแต่ละ $i$ จะไล่ตัวแปร $j$ ตั้งแต่ $[i, n)$ เราจะเก็บตัวแปร $S$ ที่เก็บผลบวกของช่วง $[i, j]$ เมื่อต้องการเลื่อนจาก $j$ ไป $j+1$ เราจะเพิ่มค่า $S$ เป็น $S = S + a[j]$ และเมื่อต้องการเปลี่ยนค่า $i$ เราจะตั้งค่า $S$ ใหม่ที่ $S = 0$ ฉนั้นในแต่ละขั้นตอนจะได้ช่วง $[i, j]$ และผลบวกของแต่ละช่วง ซึ่งสามารถนำมาหาว่าผลบวกของช่วงใหนมีค่ามากที่สุดได้ ด้านล่างคือโค้ดของอัลกอริทึมหลักนี้

```python
max_sum = 0
left_bound = -1
right_bound = -1
for i in range(0, n):
S = 0
for j in range(i, n):
S = S + a[j]
if S > max_sum:
max_sum = S
left_bound = i
right_bound = j
print(max_sum, left_bound, right_bound)
```
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi2_maxseq/solution)
1 change: 1 addition & 0 deletions md/1006.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi2_dice/solution)
1 change: 1 addition & 0 deletions md/1007.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi2_bee/solution)
1 change: 1 addition & 0 deletions md/1008.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi2_skyline/solution)
1 change: 1 addition & 0 deletions md/1009.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi2_segment/solution)
1 change: 1 addition & 0 deletions md/1010.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi2_word/solution)
1 change: 1 addition & 0 deletions md/1011.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi3_block/solution)
1 change: 1 addition & 0 deletions md/1012.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi3_cake/solution)
1 change: 1 addition & 0 deletions md/1013.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi3_express/solution)
1 change: 1 addition & 0 deletions md/1014.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi3_filter/solution)
1 change: 1 addition & 0 deletions md/1015.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi3_tiling/solution)
1 change: 1 addition & 0 deletions md/1016.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi3_treasure/solution)
1 change: 1 addition & 0 deletions md/1059.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi4_sms/solution)
1 change: 1 addition & 0 deletions md/1060.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ดูเฉลยได้ที่[นี่](https://programming.in.th/tasks/toi4_mountain/solution)
Loading