Post

백준 10944 랜덤 게임~~ 문제 풀이

백준 10944 랜덤 게임~~ 문제 풀이

백준 온라인 저지, 10944번: 랜덤 게임~~

도입

채점 프로그램이 랜덤으로 선택하는 1부터 10,000 사이의 정수를 맞추는 문제이다. 채점 프로그램은 수를 매번 랜덤으로 제시하므로 매 제출은 1/10000, 0.01% 확률로 통과할 수 있다.

이 문제를 통과하기 위해서는 가능한 한 많은 답안을 제출해야 한다. 백준 온라인 저지는 당일 누적 제출 횟수 $S$에 대하여 $10 \times ( \lfloor S / 50 \rfloor + 1 )$ 초의 제출 시간 간격 제한이 있으므로, 제출을 거듭할 수록 대기해야 하는 시간이 길어진다.

더 나아가 문제의 채점 우선 순위는 3이다. 채점 순위 3 에는 재채점도 속해있어서, 상당한 제출을 가지고 있는 문제가 재채점되면 며칠이 지나도 채점 결과를 확인하지 못할 수도 있다.

풀어보기

1e-4의 확률을 독립시행하였을 때, 70%의 상황에서 1만2천회 전후의 제출로 문제를 통과할 수 있다. 직접 1만2천회의 제출을 시도하는 것은 꽤 끈기를 요구하는 일이다. 이에 더해 제출 시간 간격 제한이 있으므로, 사실 직접 제출로 문제를 해결하는 것은 불가능하다.

일반적으로 매크로의 사용은 부적절한 것으로 여겨지나, 이 문제는 매크로의 사용이 의도되는 것으로 보인다. 따라서 Tampermonkey 유저스크립트 확장을 통해 간단한 매크로를 작성하여 사용한다.

답안

유저스크립트 파트 1: 문제 제출 페이지로의 접근을 감지하면, 답안을 작성하고 제출한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// ==UserScript==
// @name         10944 Random Game Random Submitter (Submit Part)
// @namespace    https://jonghyeon.me
// @version      1
// @description  Baekjoon Online Judge Random Game Random Submitter (Submit Part)
// @author       ShapeLayer
// @match        https://www.acmicpc.net/submit/10944
// @grant        none
// @run-at       document-end
// ==/UserScript==

function submitCode() {
  var newForm = document.createElement('form')
  newForm.id = 'newForm'
  newForm.method = 'post'
  var input__code_open = document.createElement('input')
  input__code_open.name = 'code_open'
  input__code_open.value = 'open'
  newForm.appendChild(input__code_open)
  var input__csrf_key = document.createElement('input')
  input__csrf_key.name = 'csrf_key'
  input__csrf_key.value = document.getElementsByName('csrf_key')[0].value
  newForm.appendChild(input__csrf_key)
  var input__language = document.createElement('input')
  input__language.name = 'language'
  input__language.value = '58'
  newForm.appendChild(input__language)
  var input__problem_id = document.createElement('input')
  input__problem_id.name = 'problem_id'
  input__problem_id.value = '10944'
  newForm.appendChild(input__problem_id)
  var input__source = document.createElement('input')
  input__source.name = 'source'
  input__source.value = '10'
  newForm.appendChild(input__source)

  document.getElementsByTagName('body')[0].appendChild(newForm)
  newForm.submit()
}

(function() {
  submitCode()
})()

유저스크립트 파트 2: 답안 제출 후 리다이렉트되는 채점 현황 페이지를 감지하면, 제출 시간 간격 제한만큼 대기한 후 다시 답안 제출 페이지로 리다이렉트한다. 답안 제출 페이지로 리다이렉트되면, 파트 1 스크립트가 작동하여 답안을 제출한다. 이 과정을 반복하여 많은 양의 답안을 제출한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ==UserScript==
// @name         10944 Random Game Random Submitter (Redirection Part)
// @namespace    https://jonghyeon.me
// @version      1
// @description  Baekjoon Online Judge Random Game Random Submitter (Redirection Part)
// @author       ShapeLayer
// @match        https://www.acmicpc.net/status?*problem_id=10944*
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-end
// ==/UserScript==

(function() {
  const now = new Date()
  const key = now.getFullYear() + ' ' + now.getMonth() + ' ' + now.getDate()
  var nowTried = GM_getValue(key, 0)
  GM_setValue(key, nowTried+1)
  console.log(key + ' tried: ' + nowTried + ', delayed: ' + 10*((nowTried/50)+1)*1000)
  setTimeout(() => {window.location.href='https://www.acmicpc.net/submit/10944'}, 10*((nowTried/50)+1)*1000)
})();

마무리

이 문제 해결에 얼마나 많은 양의 답안을 제출했는지는 확인하지 않았다. 다른 문제들의 재채점이 활발하게 이루어져, 대략 보름 정도가 지나서 통과를 확인하였다.