├── .gitignore ├── post-contest ├── README.md └── editorial.md ├── pre-contest ├── description │ ├── expressions.md │ ├── image-1.png │ └── README.md ├── README.md ├── solution │ └── README.md ├── problemset-construction.md └── data │ └── README.md ├── in-contest ├── README.md ├── qna.md └── data-check.md ├── .vscode └── settings.json ├── README.md └── appendix ├── testlib ├── opt.md ├── pattern.md ├── tresult.md ├── random_t.md ├── README.md ├── utils.md └── instream.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /post-contest/README.md: -------------------------------------------------------------------------------- 1 | # 대회 종료 후 2 | 3 | - [에디토리얼](editorial.md) 4 | -------------------------------------------------------------------------------- /pre-contest/description/expressions.md: -------------------------------------------------------------------------------- 1 | # 자주 사용되는 표현 2 | 3 | (TODO) 4 | -------------------------------------------------------------------------------- /in-contest/README.md: -------------------------------------------------------------------------------- 1 | # 대회 중 2 | 3 | - [질문과 답변](qna.md) 4 | - [제출 및 데이터 점검](data-check.md) 5 | -------------------------------------------------------------------------------- /pre-contest/description/image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solved-ac/arena-manual/HEAD/pre-contest/description/image-1.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "markdown.extension.toc.levels": "2..6", 3 | "markdown.extension.toc.omittedFromToc": { 4 | "*": ["## 목차"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /pre-contest/README.md: -------------------------------------------------------------------------------- 1 | # 대회 준비 2 | 3 | - [문제와 셋 구성](./problemset-construction.md) 4 | - [디스크립션](./description/README.md) 5 | - [데이터 및 채점](./data/README.md) 6 | - [풀이 및 제한 설정](./solution/README.md) 7 | -------------------------------------------------------------------------------- /pre-contest/solution/README.md: -------------------------------------------------------------------------------- 1 | # 풀이 및 제한 설정 2 | 3 | > 요약 4 | > 5 | > - C++ 풀이가 하나 이상 존재해야 합니다. 6 | > - 풀이의 정당성을 증명할 수 없는 문제는 내지 말아야 합니다. 7 | > - 메모리 제한은 1024 MB여야 합니다. 1024 MB가 아닐 경우, 디스크립션의 첫 줄에 경고해야 합니다. 8 | 9 | ## 풀이 10 | 11 | - 모든 문제에는 C++로 해결하는 풀이를 작성해야 합니다. 다만, C++로 해결하는 풀이가 정해일 필요는 없습니다. 12 | - 모든 문제에 Python 또는 PyPy로 해결하는 풀이를 작성하는 것을 권장하나, 작성하지 않아도 괜찮습니다. 13 | 14 | ## 정당성 15 | 16 | - 정해는 정당성이 증명된 것이어야 합니다. 정당성을 증명할 수 없는 문제는 출제하지 않아야 합니다. 17 | - **예)** 실수를 사용하는 문제에서, 실수 오차 범위의 상한을 보일 수 없을 경우 출제하지 말아야 합니다. 18 | 19 | ## 제한 20 | 21 | - 별다른 이유가 없을 경우, 문제의 메모리 제한은 1024 MB여야 합니다. 22 | - 메모리 제한이 1024 MB가 아닐 경우, 메모리 제한이 일반적이지 않다는 경고를 디스크립션 첫 줄에 굵은꼴로 작성하여야 합니다. 23 | - **안 좋은 예)** [BOJ 10989](https://www.acmicpc.net/problem/10989) 〈수 정렬하기〉 24 | - **좋은 예)** [BOJ 22881](https://www.acmicpc.net/problem/22881) 〈붉은색 푸른색〉 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # arena-manual 2 | 3 | [solved.ac 아레나](https://solved.ac/arena) 개최 매뉴얼 (아레나 개최 안내 – v1.2) 4 | 5 | 모든 내용은 작성 중이며, 적용하기 전까지는 참고용으로만 사용해 주시기 바랍니다. 작성 중에는 내용이 자주 변경될 수 있습니다. 6 | 7 | 이 문서에서 다음의 용어는 RFC 2119에서 규정된 각각의 용어에 대응됩니다. 8 | 9 | - "합니다": "MUST". 어떤 상황에서든 반드시 준수해야 합니다. 10 | - "하지 않습니다": "MUST NOT". 어떤 상황에서든 절대 해서는 안 되는 사항입니다. 11 | - "하는 것을 권장합니다": "SHOULD". 특별한 상황에서 그렇게 하지 않을 정당한 이유가 있으면 무시할 수 있으나, 그렇게 할 경우 신중한 고려가 필요합니다. 12 | - "하지 않는 것을 권장합니다": "SHOULD NOT". 특별한 상황에서 그렇게 할 정당한 이유가 있으면 무시할 수 있으나, 그렇게 할 경우 신중한 고려가 필요합니다. 13 | - "해도 됩니다": "MAY". 14 | 15 | ## 개요 16 | 17 | - [대회 준비](/pre-contest/README.md) (D-21) 18 | - [문제와 셋 구성](/pre-contest/problemset-construction.md) 19 | - [디스크립션](/pre-contest/description/README.md) 20 | - [데이터 및 채점](/pre-contest/data/README.md) 21 | - [풀이 및 제한 설정](/pre-contest/solution/README.md) 22 | - [대회 중](/in-contest/README.md) 23 | - [질문과 답변](/in-contest/qna.md) 24 | - [제출 및 데이터 점검](/in-contest/data-check.md) 25 | - [대회 종료 후](/post-contest/README.md) 26 | - [에디토리얼](/post-contest/editorial.md) 27 | - [부록](/appendix/README.md) 28 | - [testlib.h 비공식 문서](/appendix/testlib/README.md) 29 | - [참고할 만한 링크](/appendix/README.md#참고할_만한_링크) 30 | -------------------------------------------------------------------------------- /in-contest/qna.md: -------------------------------------------------------------------------------- 1 | # 질문과 답변 2 | 3 | 아레나 출제 및 검수진은 일부 예외를 제외하고 아레나 진행 도중 발생하는 참가자의 모든 질문에 대해 답변해야 합니다. 4 | 5 | 다음을 답변 프리셋으로 지정하고 사용하는 것을 권장합니다. 6 | 7 | - 네. / Yes. 8 | - 아니오. / No. 9 | - 답변할 수 없습니다. / Cannot answer. 10 | - 문제와 관련 없는 질문에는 답변하지 않습니다. / Cannot answer questions unrelated to the problem. 11 | - 문제를 다시 읽어 주세요. / Please read the problem statement again. 12 | - 질문을 명확하게 작성해 주세요. / Please clarify your question. 13 | 14 | ## 형평성 15 | 16 | 답변은 참가자 간의 형평성을 고려해 작성하여야 합니다. 17 | 18 | - '네' 혹은 '아니오' 중 하나로 답변할 수 있는 질문 외에는 질문에 대한 의미 있는 답을 제공하지 않는 것을 권장합니다. 19 | - 지문이 난해하거나 여러 의미로 해석될 수 있는 경우를 제외하고, 참가자가 독해할 수 있음에도 불구하고 지문 이해 실패로 인하여 발생하는 질문에는 답변하지 않아야 합니다. 20 | - 추가 예제, 또는 특정 입력의 출력 결과를 요청하는 질문에는 답변하지 않아야 합니다. 21 | - 문제의 해결 방법 일부 또는 전체, 특정 코드의 실행 결과를 요청하는 질문에는 답변하지 않아야 합니다. 22 | - 기타 답변하는 것으로 참가자에게 이득을 줄 만한 질문에는 답변한다면 공개 답변으로 하여 다른 참가자 모두가 질문과 답변을 열람할 수 있도록 하여야 합니다. 23 | 24 | ## 잠재적 문제 오류 발견 25 | 26 | 참가자가 문제 오류를 지적하는 경우, 아레나 출제 및 검수진은 문제 오류를 확인하여야 합니다. 27 | 28 | - 문제 오류가 발견된 경우 아레나 출제 및 검수진은 문제 오류를 즉시 수정해야 합니다. 29 | - 문제 오류를 수정한 후 수정되었음을 공개 답변 및 공지사항으로 알려야 합니다. 30 | 31 | 오류 수정 이후의 대응에 대하여서는 [제출 및 데이터 점검/문제 오류 발견 후 대응](./data-check.md#문제-오류-발견-후-대응)을 참조합니다. 32 | 33 | ## 부적절한 질문 34 | 35 | 아래 내용을 포함한 질문에는 답변하지 않아야 합니다. 36 | 37 | - 참가자의 개인 정보 등이 포함된 질문 38 | - 비속어, 욕설 등이 포함된 질문 39 | -------------------------------------------------------------------------------- /in-contest/data-check.md: -------------------------------------------------------------------------------- 1 | # 제출 및 데이터 점검 2 | 3 | 아레나 출제 및 검수진은 잠재적 문제 오류를 발견하기 위하여 대회 진행 중 참가자의 제출을 적극적으로 점검하여야 합니다. 4 | 5 | 꼼꼼하게 점검해야 하는 제출은 아래의 예를 포함하나 아래의 예에 한정하지 않습니다. 6 | 7 | - 문제 각각의 첫 몇 개의 정답 및 오답 제출 8 | - 문제를 맞을 것으로 예상하는 참가자의 오답 제출 9 | - 정답자가 많지 않을 것으로 예상하는 문제의 제출 10 | 11 | ## 문제 오류 발견 후 대응 12 | 13 | 잠재적인 및 실존하는 문제 오류를 발견하였을 경우, 아레나 출제 및 검수진은 아래의 절차를 따라야 합니다. 14 | 15 | - A) **정답**으로 판정되어야 할 제출이 **오답**으로 판정되는 경우가 발생한 경우 16 | - B) **오답**으로 판정되어야 할 제출이 **정답**으로 판정되는 경우가 발생한 경우 17 | 18 | | 상황 | 공지 | 재채점 | 대회 종료 후 레이팅 반영 | 19 | | ------------------------- | ---- | ------ | ------------------------ | 20 | | A 및 B 모두 발생 | O | X | X | 21 | | A만 발생 | O | O | X\* | 22 | | B만 발생 | X\* | X | O\* | 23 | | A 및 B 모두 발생하지 않음 | X | O | O | 24 | 25 | ### A, B 모두가 발생한 경우 26 | 27 | - 문제 오류를 발견한 즉시 공지합니다. 28 | - 대회 종료 후 전체 참가자에 대하여 대회 결과에 대한 레이팅을 반영하지 않도록 합니다. 29 | - 대회가 종료된 후 7일 안에 문제 오류 수정 및 재채점 수행을 마칩니다. 30 | 31 | ### A만 발생한 경우 32 | 33 | - 문제 오류를 발견한 즉시 공지하고, 재채점할 것임을 알립니다. 34 | - 최대한 해당 제출들을 정답으로 처리할 수 있도록 문제를 수정하고 재채점합니다. 35 | - **예)** 지문에서 $10^5$ 이하 크기의 배열이 주어진다고 했으나 실제 데이터는 $10^6$ 이하 크기의 배열을 포함하고 있었을 경우, 지문의 제한을 $10^6$으로 수정하는 대신, $10^5$ 초과 크기의 배열을 포함하고 있는 데이터를 전부 삭제합니다. 36 | - **영향을 받은 참가자가 5명 초과라면**, 대회 종료 후 전체 참가자에 대하여 대회 결과에 대한 레이팅을 반영하지 않도록 합니다. 37 | - 영향을 받은 참가자가 5명 이하인 경우, 영향을 받은 참가자에게 개별 연락하여 레이팅 반영 의사를 묻고, 이를 따르도록 합니다. 38 | 39 | ### B만 발생한 경우 40 | 41 | > **Note** 42 | > BOJ는 대회 중에는 맞은 제출이 틀린 제출로 바뀌는 재채점을 허용하지 않습니다. 43 | 44 | - 데이터가 충분히 강하지 않아서 발생한 일일 경우 45 | - 대회가 종료된 후 7일 안에 문제 오류 수정 및 재채점 수행을 마칩니다. 46 | - 별다른 공지는 진행하지 않습니다. 47 | - 이외의 중대 결함에 의한 일일 경우 48 | - 문제 오류를 발견한 즉시 공지합니다. 49 | - 대회 종료 후 전체 참가자에 대하여 대회 결과에 대한 레이팅을 반영하지 않도록 합니다. 50 | - 대회가 종료된 후 7일 안에 문제 오류 수정 및 재채점 수행을 마칩니다. 51 | 52 | ### A와 B 모두 발생하지 않은 경우 53 | 54 | - 문제를 수정하고 재채점합니다. 별다른 공지는 진행하지 않습니다. 55 | -------------------------------------------------------------------------------- /appendix/testlib/opt.md: -------------------------------------------------------------------------------- 1 | # opt 2 | 3 | - 해당 내용: **Generator** 4 | 5 | testlib.h는 generator 옵션을 조금 더 쉽게 파싱할 수 있게 `opt` 계열 메서드들을 제공합니다. 아래 `opt` 등장 이전의 코드와 `opt` 등장 이후의 코드를 비교하면, 확실히 `opt`를 사용하는 것이 더 간결하고 읽기 쉬운 것을 알 수 있습니다. 6 | 7 | - `opt` 등장 이전 8 | 9 | ``` 10 | gen 100000 500 true 11 | ``` 12 | 13 | ```cpp 14 | int N = atoi(argv[1]); 15 | int M = atoi(argv[2]); 16 | bool isTree = (strcmp(argv[3], "true") == 0); 17 | ``` 18 | 19 | - `opt` 등장 이후 20 | 21 | ``` 22 | gen -n100000 -m500 --is-tree 23 | ``` 24 | 25 | ```cpp 26 | int N = opt("n"); 27 | int M = opt("m"); 28 | bool isTree = opt("is-tree"); 29 | ``` 30 | 31 | ## 형식 32 | 33 | `opt`가 지원하는 generator 옵션 형식은 아래 4가지 중 하나입니다. keyName은 알파벳으로 시작해야 합니다. value는 어떤 형식이든 가능하나, 수인 경우 과학적 표기법도 가능합니다. 34 | 35 | - `-keyName=value` 혹은 `--keyName=value` 36 | - `-n=10000`, `--num-segments=1e6` 37 | - `-keyName value` 혹은 `--keyName value` 38 | - `-n 10000`, `--num-segments 1e6` 39 | - `-kValue` 혹은 `--kValue` 40 | - keyName은 한 글자 알파벳이어야 하며, 이어지는 value는 수여야 합니다. 41 | - `-n10000`, `--m1e6` 42 | - `-boolProperty` 혹은 `--boolProperty` 43 | - `-isDag`, `--is-sorted` 44 | 45 | ## 메서드 46 | 47 | ### opt 48 | 49 | - `template T opt(const std::string &key)` 50 | - `std::string opt(const std::string &key)` 51 | - `T`: 반환할 값의 타입. 52 | - `key`: 옵션의 이름. 53 | 54 | 옵션 `key`에 해당하는 값을 반환합니다. `opt`을 제외한 경우에 옵션 `key`를 찾지 못했을 경우, [`_fail`](tresult.md#_fail) 결과로 종료합니다. 55 | 56 | `T`에 따라 다른 동작을 합니다. 57 | 58 | - `opt("key")`는 `key`를 갖는 옵션을 `std::string`으로 반환합니다. 59 | - `opt("key")`의 동작은 `opt("key")`와 같습니다. 60 | - `opt("key")`, `opt("key")` 등은 옵션 `key`를 정수로 취급하여 파싱합니다. 파싱에 실패하는 경우, [`_fail`](tresult.md#_fail) 결과로 종료합니다. `__int128` 등의 비표준 자료형에서의 동작을 보장하지 않습니다. 61 | - `opt("key")`의 경우 옵션 `key`를 실수로 취급하여 파싱합니다. 파싱에 실패하는 경우, [`_fail`](tresult.md#_fail) 결과로 종료합니다. `__float128` 등의 비표준 자료형에서의 동작을 보장하지 않습니다. 62 | - `opt("key")`의 경우 옵션 `key`가 존재하고 `true`와 `1` 중 하나의 값을 가지면 `true`를 반환하며, 옵션 `key`가 존재하지 않거나 `false`와 `0` 중 하나의 값을 가지면 `false`를 반환합니다. 이외의 경우 [`_fail`](tresult.md#_fail) 결과로 종료합니다. 63 | 64 | ### has_opt 65 | 66 | - `bool has_opt(const std::string &key)` 67 | - `key`: 옵션의 이름. 68 | 69 | 옵션 `key`가 존재하는지 여부를 반환합니다. 70 | -------------------------------------------------------------------------------- /appendix/testlib/pattern.md: -------------------------------------------------------------------------------- 1 | # pattern 2 | 3 | `pattern`은 정규 표현식과 비슷한 문법의 오토마타 표현식을 처리하는 클래스입니다. 다음 문법이 지원됩니다. 4 | 5 | - `Alice|Bob`: `Alice` 혹은 `Bob`. 6 | - `A?`: `A`가 0번 혹은 1번 등장. 7 | - `A*`: `A`가 0번 이상 등장. (generation에서는 사용 불가) 8 | - `A+`: `A`가 1번 이상 등장. 9 | - `A{m}`: `A`가 정확히 `m`번 등장. 10 | - `A{m,n}`: `A`가 `m`번 이상, `n`번 이하 등장. 11 | - `[a-z]`: 소문자 `a`부터 `z`까지의 문자 중 하나. 12 | - `[ABC]`: `A`, `B`, `C` 중 하나. 13 | - `[^ABC]`: `A`, `B`, `C`를 제외한 문자 중 하나. (generation에서는 사용이 권장되지 않음) 14 | - `()`: 그룹. 15 | 16 | 특수 문자는 `\`로 escape할 수 있습니다. 17 | 18 | 다음은 몇 가지 `pattern`의 예입니다. 19 | 20 | - `[Yy][Ee][Ss]|[Nn][Oo]`: 대소문자 구별 없이, `yes` 혹은 `no`. 21 | - `[ABC]{1,20}`: `A`, `B`, `C`만으로 구성된 길이 1 이상 20 이하의 문자열. 22 | - `0|-?[1-9][0-9]{0,99}`: 100글자 미만의 정수. 23 | 24 | 길이 $N$의 `pattern` 등을 생성할 때에는 [`format`](./utils.md#format)을 사용하는 것이 좋습니다. 25 | 26 | - `format("[AB]{%d}", N)`: `A` 또는 `B`만으로 구성된 길이 $N$의 문자열. 27 | 28 | 같은 `pattern`을 자주 사용한다면, 일반적인 정규식과 비슷하게 `pattern p("[0-9]+")` 등으로 미리 정의해 두고 사용하는 것이 실행 시간 면에서 더 효율적입니다. 29 | 30 | ## 일반적인 정규식과 다른 점 31 | 32 | `pattern`이 지원하는 표현식은 일반적인 정규식과 약간의 차이점이 존재합니다. 33 | 34 | - 모든 문자를 매칭하는 `.` 연산자는 지원하지 않습니다. 35 | - 띄어쓰기 ` `는 무시합니다. 표현식 `No solution`은 `Nosolution`을 매칭합니다. 띄어쓰기 문자 자체를 매칭하고 싶다면, `\ `를 사용해야 합니다. 36 | - `[^ABC]`는 일반 정규식에서는 `A`, `B`, `C`를 제외한 모든 문자를 매칭하지만, `pattern`에서는 `\0` = 0부터 `þ` = 254까지의 문자 중 `A`, `B`, `C`를 제외한 문자를 매칭합니다. 그러므로 generator에서 `[^ABC]`를 사용하는 것은 권장되지 않습니다. 37 | - 매칭 알고리즘은 그리디합니다. 예를 들어, 패턴 `[0-9]?1`에 `1`을 매칭시키는 경우, 두 번째 문제를 고려하지 않은 채로 첫 번째 문자를 `[0-9]?`에 매칭할 수 있으면 그렇게 합니다. 그러므로, `pattern` 표현식에서 `1`은 `[0-9]?1`에 매칭되지 않습니다. 38 | - `|` 연산자의 매칭에는 브루트포싱 알고리즘을 사용합니다. 39 | 40 | 별개로, 현재 버전에서 `|`와 `()`를 섞어 쓰는 경우에서 표현식이 잘 동작하지 않는 경우가 발견되고 있습니다. 따라서 `()`는 피해서 사용하는 것을 권장하며, 조금 더 포괄적인 표현식으로 입력받은 후 `std::regex`와 [`ensuref`](utils.md#ensuref)로 검증하는 것을 권장합니다. 41 | 42 | ## 메서드 43 | 44 | ### pattern::pattern 45 | 46 | - `pattern(std::string s)` 47 | - `s`: 표현식. 48 | 49 | `pattern`을 생성합니다. 50 | 51 | ### pattern::src 52 | 53 | - `std::string pattern::src() const` 54 | 55 | `pattern`에 사용된 표현식을 반환합니다. 56 | 57 | ### pattern::matches 58 | 59 | - `bool pattern::matches(const std::string& s) const` 60 | - `s`: 매칭할 문자열. 61 | 62 | `s`가 `pattern`에 매칭되는지 여부를 반환합니다. 63 | 64 | ### pattern::next 65 | 66 | - `std::string pattern::next(random_t &rnd) const` 67 | 68 | = [random_t::next(std::string)](./random_t.md#random_tnextstdstring) 69 | -------------------------------------------------------------------------------- /appendix/testlib/tresult.md: -------------------------------------------------------------------------------- 1 | # TResult 2 | 3 | `enum TResult`는 [`quit`](utils.md#quit) 및 [`quitf`](utils.md#quitf) 등의 메서드에서 사용되는 채점 결과를 나타내는 열거형입니다. 4 | 5 | Checker의 일부분인 아래 코드에서 [`_wa`](#_wa)는 `TResult`의 값입니다. 6 | 7 | ```cpp 8 | quitf(_wa, "Extra tokens found in participant's answer"); 9 | ``` 10 | 11 | 일반적으로 Validator와 Generator에서는 이 결과를 직접 사용하여 종료하는 경우는 없습니다. 12 | 13 | - 참고: [Checker](README.md#checker) 14 | - 참고: [BOJ Help: 채점 결과](https://help.acmicpc.net/judge/info) 15 | 16 | ## 값 및 각 플랫폼에서 대응되는 값 17 | 18 | | 값 | Polygon | BOJ | Codeforces | 19 | | :---------------: | :-----: | :------------------------- | :----------------- | 20 | | [`_ok`](#_ok) | OK | 맞았습니다!! | Accepted | 21 | | [`_wa`](#_wa) | WA | 틀렸습니다 | Wrong Answer | 22 | | [`_pe`](#_pe) | PE | 출력 형식이 잘못되었습니다 | Presentation Error | 23 | | [`_fail`](#_fail) | FL | 틀렸습니다 | Fail | 24 | 25 | 이외의 채점 결과(시간 초과, 메모리 초과, 런타임 에러 등)는 채점기에서 직접 발생시킬 수 없으며, 각 플랫폼의 채점 시스템에서 자동 판정합니다. 26 | 27 | 부분 점수로 종료하려면 [`quitp`](utils.md#quitp)를 사용합니다. 28 | 29 | ## 값 30 | 31 | ### \_ok 32 | 33 | - `TResult _ok = 0` 34 | 35 | 참가자의 출력이 정답임을 나타내는 값. 36 | 37 | BOJ에서 이 값은 초록색 **맞았습니다!!**(`4`)에 대응됩니다. Polygon에서 이 값은 **OK**(**OK**)에 대응됩니다. 38 | 39 | ### \_wa 40 | 41 | - `TResult _wa = 1` 42 | 43 | 참가자의 출력이 오답임을 나타내는 값. 44 | 45 | BOJ에서 이 값은 **틀렸습니다**(`6`)에 대응됩니다. Polygon에서 이 값은 **Wrong Answer**(**WA**)에 대응됩니다. 46 | 47 | ### \_pe 48 | 49 | - `TResult _pe = 2` 50 | 51 | 참가자의 출력이 형식에 맞지 않음을 나타내는 값. 52 | 53 | BOJ에서 이 값은 **출력 형식이 잘못되었습니다**(`5`)에 대응됩니다. Polygon에서 이 값은 **Presentation Error**(**PE**)에 대응됩니다. 54 | 55 | ### \_fail 56 | 57 | - `TResult _fail = 3` 58 | 59 | 참가자의 출력을 바탕으로 채점을 진행할 수 없음을 나타내거나, 채점 중 오류가 발생했음을 나타내는 값. 60 | 61 | BOJ에서 이 값은 **틀렸습니다**(`6`)에 대응됩니다. Polygon에서 이 값은 **Fail**(**FL**)에 대응됩니다. 62 | 63 | ### \_dirt 64 | 65 | - `TResult _dirt = 4` 66 | 67 | 일반적으로 직접 사용하지 않습니다. 내부적으로만 사용되는 값입니다. 68 | 69 | 참가자의 출력에 불필요한 토큰이 더 남아 있음을 나타내는 값. 채점기가 [`_ok`](#_ok) 혹은 [`quitp`](utils.md#quitp)로 종료했을 때, 참가자의 출력에 토큰이 더 남아 있을 경우 채점기는 자동으로 이 값으로 종료하며, [`_pe`](#_pe)로 종료한 것과 같은 결과를 발생시킵니다. 70 | 71 | ### \_points 72 | 73 | - `TResult _points = 5` 74 | 75 | 일반적으로 직접 사용하지 않습니다. 내부적으로만 사용되는 값입니다. 76 | 77 | 참가자가 어떤 점수 값을 획득하였음을 의미하는 값. [`quitp`](utils.md#quitp)로 종료했을 때 내부적으로 사용되는 값입니다. 78 | 79 | ### \_unexpected_eof 80 | 81 | - `TResult _unexpected_eof = 8` 82 | 83 | 일반적으로 직접 사용하지 않습니다. 내부적으로만 사용되는 값입니다. 84 | 85 | 참가자의 출력에서 토큰을 더 읽을 수 없음을 나타내는 값. 채점기가 토큰을 더 읽을 수 없을 때, [`_pe`](#_pe)로 종료한 것과 같은 결과를 발생시킵니다. 86 | 87 | ### \_partially 88 | 89 | - `TResult _partially = 16` 90 | 91 | 예전의 채점 방식에서만 사용되는 값입니다. 현재는 대신 [`quitp`](utils.md#quitp)를 사용하는 것을 권장합니다. 92 | 93 | 일반적으로 직접 사용하지 않습니다. 내부적으로만 사용되는 값입니다. 94 | 95 | 참가자가 어떤 점수 값을 획득하였음을 의미하는 값. `quitf(_partially, ...)` 대신 매크로 `_pc`를 이용하여 `quitf(_pc(score), ...)`를 사용하여야 하며, 이때 $0 \le \texttt{score} \le 200$으로, 200점을 만점으로 취급합니다. 96 | -------------------------------------------------------------------------------- /pre-contest/problemset-construction.md: -------------------------------------------------------------------------------- 1 | # 문제와 셋 구성 2 | 3 | > 요약 4 | > 5 | > - 문제의 난이도와 주제는 고르게 분포되어 있어야 합니다. 6 | > - 기획하려는 문제가 BOJ 가이드라인을 지키는지 점검합니다. 7 | > - 기획하려는 문제의 난이도가 실제 난이도와 큰 괴리를 보일 가능성은 없는지 점검합니다. 8 | > - 기획하려는 문제가 Not ratable 또는 레이팅을 주지 않는 문제가 될 가능성이 있는지 점검합니다. 9 | 10 | 문제와 셋 구성은 대회의 전반적인 난이도를 대략적으로 계획하는 단계입니다. 11 | 12 | 아레나는 5시간 이하이면서 15문제 이하인 대회에 대하여 각 커뮤니티 대회의 포맷을 존중합니다. 이하 내용은 커뮤니티 대회의 포맷을 따르는 것으로 합니다. 13 | 14 | ## 목차 15 | 16 | - [목차](#목차) 17 | - [참가 대상 및 난이도의 상/하한 설정](#참가-대상-및-난이도의-상하한-설정) 18 | - [난이도 분포 목표 설정](#난이도-분포-목표-설정) 19 | - [문제 수 대비 대회 시간 설정](#문제-수-대비-대회-시간-설정) 20 | - [주제 목표 설정](#주제-목표-설정) 21 | - [점검 사항](#점검-사항) 22 | - [BOJ 가이드라인](#boj-가이드라인) 23 | - [난이도 예측](#난이도-예측) 24 | - [해결가능성 등](#해결가능성-등) 25 | 26 | ## 참가 대상 및 난이도의 상/하한 설정 27 | 28 | - 참가 대상의 하한은 다음 중 하나여야 합니다: Unrated, B, A, S, SS. 29 | - 참가 대상의 상한은 다음 중 하나여야 합니다: A+, S+, SS, SS+, SSS, SSS+, X. 30 | 31 | 난이도의 상/하한은 아레나 참가 대상과 대략적으로 연동됩니다. 목표하는 참가 대상에 따라 난이도의 상/하한을 결정하거나, 이미 상/하한이 준비되어 있다면, 아레나 참가 대상을 결정할 수 있습니다. 32 | 33 | | 참가 대상의 하한 | 권장하는 난이도 하한 | 34 | | ---------------- | -------------------- | 35 | | Unrated | Bronze | 36 | | B | Bronze - Silver | 37 | | A | Bronze - Silver | 38 | | S | Silver - Gold | 39 | | SS | Gold | 40 | 41 | | 참가 대상의 상한 | 권장하는 난이도 상한 | 42 | | ---------------- | -------------------- | 43 | | A+ | Gold - Platinum | 44 | | S+, SS | Platinum - Diamond | 45 | | SS+, SSS | Diamond | 46 | | SSS+, X | Diamond - Ruby | 47 | 48 | ## 난이도 분포 목표 설정 49 | 50 | 문제의 난이도는 상/하한 사이에서 적당히 고르게 분포되는 것을 목표로 하여야 합니다. 이는 참가자에게 연속적으로 가시적인 문제해결 목표를 부여하기 위함입니다. 51 | 52 | - **예 1:** 9문제 Unrated - SS+ 대회인 경우 53 | - 권장되는 문제 난이도의 상/하한은 Bronze - Diamond입니다. 54 | - 이 경우, Bronze 2문제, Silver 2문제, Gold 2문제, Platinum 2문제, Diamond 1문제로 구성할 수 있습니다. 55 | - **예 2:** 6문제 SS - X 대회인 경우 56 | - 권장되는 문제 난이도의 상/하한은 Gold - Ruby입니다. 57 | - 이 경우, Gold 1문제, Platinum 2문제, Diamond 이상 3문제로 구성할 수 있습니다. 58 | 59 | 구성 목표가 정해지면 해당 목표를 기반으로 문제를 준비합니다. 60 | 61 | - 이미 문제들이 준비되어 있다면, 고른 분포를 만들기 위해 문제를 적당히 수정, 추가 및 삭제하는 것을 목표로 합니다. 62 | - 추가하려는 문제는 시간 내에 풀이를 검증할 수 있는 문제를 새로 제작할 수 있어야 합니다. 63 | - 대회까지의 시간이 많이 남지 않았다면 상한을 만족하기 위해 고난도의 문제를 추가하려고 하는 것은 권장하지 않으며, 이 경우 상한을 낮추는 것을 고려해야 합니다. 64 | 65 | 최종 난이도는 설정한 난이도 분포를 그대로 따라가지 않아도 괜찮습니다. 66 | 67 | ## 문제 수 대비 대회 시간 설정 68 | 69 | 대회의 시간이 문제 수와 난이도 상한에 비해 적절한지 점검합니다. 70 | 71 | - 여러 사항이 고려되어야 하지만, 대부분의 경우 3문제 당 1시간 정도로 설정하는 것이 좋습니다. 72 | 73 | ## 주제 목표 설정 74 | 75 | 아레나 문제 구성에서 주제의 분포는 참가자들이 편파적이지 않다고 느낄 만하도록 구성되어야 합니다. 76 | 77 | - 특정 주제의 문제가 대회 전체에 걸쳐 너무 많이 존재한다면, 문제를 삭제하거나 수정해야 합니다. 78 | - 다만, 대주제로 간주될 수 있을 만한 것들은 다소 자주 등장해도 괜찮습니다. **예:** 수학, DP, 애드 혹 등. 79 | 80 | ## 점검 사항 81 | 82 | 난이도와 주제 분포 목표를 설정하여 문제를 기획한 후 다음 사항들을 점검합니다. 83 | 84 | ### BOJ 가이드라인 85 | 86 | 기획하려는 문제가 BOJ 가이드라인을 지키는지 확인해야 합니다. (참고: [BOJ Help: 문제 출제 안내](https://help.acmicpc.net/problem/add)) 87 | 88 | - 기획하려는 문제의 완성도를 보장하기 어려운가? 89 | - 기획하려는 문제가 단순히 알고리즘을 구현하는 문제인가? 90 | - 기획하려는 문제의 풀이가 해당 난이도의 문제들을 주로 해결하는 사람들에게 이미 잘 알려져 있는가? 91 | 위 내용 중 하나라도 해당된다면, 문제를 수정하거나 삭제해야 합니다. 92 | 93 | ### 난이도 예측 94 | 95 | 기획하려는 문제의 난이도가 실제 난이도와 큰 괴리를 보일 가능성은 없는지 점검해야 합니다. 96 | 97 | - 출제자는 이미 풀이를 알고 있으므로 문제의 난이도를 저평가할 위험이 상당히 높습니다. 98 | - 문제 난이도는 출제자의 주관보다는, 해당 난이도의 문제들을 주로 해결하는 사람들이 해당 문제의 풀이를 모르는 상태일 때의 입장에서 판단해야 합니다. 99 | 100 | ### 해결가능성 등 101 | 102 | 기획하려는 문제가 Not ratable 또는 레이팅을 주지 않는 문제가 될 가능성이 있는지 점검해야 합니다. (참고: [난이도 책정 가이드라인](https://solved.ac/guideline)) 103 | 104 | - 문제 상황만을 근거로 첫 번째 제출의 오답 확률을 0.01% 미만으로 낮출 수 없는가? 105 | - 가장 쉬운 방법으로 해결하기 위해 필요한 지식이 알고리즘 문제해결 분야에서 일반적으로 요구하는 지식과 현저히 멀고, 그것을 문제 상황과 사회적 상식만을 사용해 추론하기 힘든 문제가 있는가? 106 | - 물리학, 비해석적 기하학, 경제, 정치, 스타트링크 사무실 등 일반적으로 요구되지 않는 지식에 대한 정보가 지문에 주어지지 않으며, 주어지지 않은 정보를 모르는 사람이 풀 수 없는 문제는 Not ratable입니다. 107 | - OEIS를 비롯한 인터넷 사이트에서 문제에 대한 지식 없이 해당 문제의 수열이나 점화식을 검색해서 문제를 쉽게 해결할 수 있는가? 108 | - 완전히 같은 다른 문제가 이미 존재하는가? 109 | 110 | 위 내용 중 하나라도 해당된다면, 문제를 수정하거나 삭제해야 합니다. 111 | -------------------------------------------------------------------------------- /appendix/README.md: -------------------------------------------------------------------------------- 1 | # 부록 2 | 3 | - [testlib.h 비공식 문서](/appendix/testlib/README.md) 4 | - [참고할 만한 링크](#참고할_만한_링크) 5 | 6 | ## 참고할 만한 링크 7 | 8 | ### 타 플랫폼 또는 대회의 출제 규칙 9 | 10 | - UCPC, [《UCPC 디스크립션 작성 및 포매팅 컨벤션》](https://github.com/ucpcc/problemsetting-guidelines), 전국 대학생 프로그래밍 대회 동아리 연합 11 | - BOJ, [《BOJ Stack 안내/문제》](https://stack.acmicpc.net/guide/problem), 스타트링크 12 | - Codeforces, [_Polygon Advices_](https://docs.google.com/document/d/e/2PACX-1vRhazTXxSdj7JEIC7dp-nOWcUFiY8bXi9lLju-k6vVMKf4IiBmweJoOAMI-ZEZxatXF08I9wMOQpMqC/pub), Nikolay [KAN](https://codeforces.com/profile/KAN) Kalinin 13 | - Codeforces, [_How to set a round on Codeforces_](https://codeforces.com/blog/entry/85259), Nikolay [KAN](https://codeforces.com/profile/KAN) Kalinin 14 | - CodeChef, [_Become a Problem Setter_](https://www.codechef.com/problemsetting), Coding Chef Private Limited 15 | - CodeChef, [_How to set a problem in CodeChef monthly contest (step-by-step)_](https://codechef.notion.site/How-to-set-a-problem-in-CodeChef-monthly-contest-step-by-step-017353d68d0b4ea784e6648c350e50df), Alex [Um_nik](https://www.codechef.com/users/um_nik) Danilyuk 16 | - DM:OJ, [_Contest Creation Guide_](https://dmoj.ca/help/externalcontests/), DMOJ Staff 17 | 18 | ### 문제 작성 일반 19 | 20 | - SW 멤버십 기술 블로그, [《프로그래밍 대회 출제 체크리스트》](https://infossm.github.io/blog/2021/12/18/checklist/) ([GitHub](https://github.com/infossm/infossm.github.io/blob/master/_posts/2021-12-18-checklist.md)), [djm01378](https://infossm.github.io/authors/djm03178/), 2021년 12월 18일 21 | - SW 멤버십 기술 블로그, [《프로그래밍 문제 출제하기》](https://infossm.github.io/blog/2020/11/21/problemsetting/) ([GitHub](https://github.com/infossm/infossm.github.io/blob/master/_posts/2020-11-21-problemsetting.md)), [jh05013](https://infossm.github.io/authors/jh05013/), 2020년 11월 21일 22 | - 욱제 블로그, [《[잡담] 내가 문제를 내는 방법》](https://wookje.dance/2019/08/29/how-to-make-problem/), [권욱제](https://github.com/wookje), 2019년 8월 29일 23 | - TopCoder Blog, [_How to Come Up with Problem Ideas_](https://www.topcoder.com/blog/how-to-come-up-with-problem-ideas/), Harshit Mehta, 2019년 5월 2일 24 | - Codeforces, [_On problemsetting_](https://codeforces.com/blog/entry/70178) ([2](https://codeforces.com/blog/entry/73015)), Anton [antontrygubO_o](https://codeforces.com/profile/antontrygubO_o) Trygub 25 | - YouTube, [《두 번째 startlink.live: 김재홍 (xhark) - 알고리즘 문제 출제 전략》](https://www.youtube.com/watch?v=C7kKs4dT0V8) ([SlideShare](https://www.slideshare.net/startlinkio/startlinklive-xhark)), [스타트링크](https://www.youtube.com/@StartlinkIo), 2017년 2월 22일 26 | - YouTube, [《신촌 대학 알고리즘 대회 출제진이 알려주는, 알고리즘 대회에서 문제 출제하기 a to b》](https://www.youtube.com/watch?v=7VRNOGQ-MCQ) ([SlideShare](https://www.slideshare.net/SesangCho/ps-a-to-bpdf)), [저세상개발자](https://www.youtube.com/@worlddev), 2022년 7월 17일 27 | - Telegraph, [_Создание задач_](https://telegra.ph/Sozdanie-zadach-06-17), Vladimir [voidmax](https://codeforces.com/profile/voidmax) Romanov, 2019년 6월 17일 28 | 29 | ### 출제 분야별 참조 사항 30 | 31 | - shifted, [《실수의 실수: 스페셜 저지만 붙인다고 끝나는 것이 아니다》](https://blog.shift.moe/2022/10/31/on-floating-point-errors/), [shiftpsh](https://shiftpsh.com), 2022년 10월 31일 32 | - SW 멤버십 기술 블로그, [《잘못 구현한 다익스트라 알고리즘 저격하기》](https://infossm.github.io/blog/2019/01/09/wrong-dijkstra/) ([GitHub](https://github.com/infossm.github.io/blob/master/_posts/2019-01-09-wrong-dijkstra.md)), [djm01378](https://infossm.github.io/authors/djm03178/), 2019년 1월 9일 33 | 34 | ### Polygon 및 testlib.h 35 | 36 | - Darkkcyan blog, [_Polygon.Codeforces Tutorial - A Guide to Problem Preparation_](https://quangloc99.github.io/posts/polygon-codeforces-tutorial/), Tran [quangloc99](https://quangloc99.github.io/) Quang Loc, 2021년 7월 25일 37 | - 티스토리, [《시리즈: Polygon》](https://evenharder.tistory.com/category/Polygon), [evenharder](https://evenharder.tistory.com/), 2015년 7월 22일 38 | - SW 멤버십 기술 블로그, [《testlib 사용하기》](https://infossm.github.io/blog/2021/05/14/testlib/) ([GitHub](https://github.com/infossm/infossm.github.io/blob/master/_posts/2021-05-14-testlib.md)), [djm01378](https://infossm.github.io/authors/djm03178/), 2021년 5월 14일 39 | 40 | ### 출제 경험 41 | 42 | > 문제 셋 구성 및 문제의 출제의 과정이 언급되어 대회 개최자가 참고하여 도움을 얻을 수 있을 만한 글들을 포함합니다. 43 | 44 | - SW 멤버십 기술 블로그, [《UCPC 2020 출제 후기》](https://infossm.github.io/blog/2020/08/18/ucpc-retrospect-evenharder/) ([GitHub](https://github.com/infossm/infossm.github.io/blob/master/_posts/2020-08-18-ucpc-retrospect-evenharder.md)), [evenharder](https://infossm.github.io/authors/evenharder/), 2020년 8월 18일 45 | - shifted, [《UCPC 2020을 개최했습니다》](https://blog.shift.moe/2020/10/21/ucpc-2020/), [shiftpsh](https://shiftpsh.com), 2020년 10월 21일 46 | - 네이버 블로그, [《2020 서강대학교 프로그래밍 대회 개최 후기 (중)》](https://blog.naver.com/raararaara/222161672176), [롸](https://blog.naver.com/raararaara), 2020년 12월 3일 47 | - 티스토리, [《제2회 한국항공대학교 프로그래밍 경진대회(KAUPC) 개최 후기》](https://hello70825.tistory.com/494), [70825](https://hello70825.tistory.com/), 2022년 9월 19일 48 | -------------------------------------------------------------------------------- /post-contest/editorial.md: -------------------------------------------------------------------------------- 1 | # 에디토리얼 2 | 3 | > 요약: 4 | > 5 | > - 대회 종료 후 1일 이내로 에디토리얼을 전달해야 합니다. 6 | > - 에디토리얼은 문제별로, [GitHub Flavored Markdown](https://github.github.com/gfm/) 스펙에 맞도록 `.md` 파일로 작성합니다. 7 | > - 에디토리얼은 맞춤법과 포매팅을 잘 준수해야 하며, 해당 문제에 도전하는 참가자들이 해당 문제를 해결하는 데에 도움이 되는 내용을 포함해야 합니다. 8 | 9 | ## 에디토리얼 작성 10 | 11 | 대회 종료 후 1일 이내로 에디토리얼을 작성하고, 솔브드 관계자에게 전달해야 합니다. 파일은 [GitHub Flavored Markdown](https://github.github.com/gfm/) 스펙에 맞는 `.md` 포맷이어야 합니다. 12 | 13 | - 에디토리얼은 UCPC 가이드라인의 지문부 스펙을 지켜 작성하는 것을 권장합니다. 14 | - 에디토리얼은 맞춤법을 지켜야 합니다. 15 | - 에디토리얼의 문장과 수식은 잘 포매팅되어 있어야 합니다. 16 | 17 | ## 에디토리얼의 내용 18 | 19 | - 에디토리얼은 해당 문제에 도전하는 참가자들이 해당 문제를 해결하는 데에 도움이 되는 내용을 포함해야 합니다. 20 | - **예)** 아무리 쉬운 문제이더라도, '문제가 제시한 내용을 그대로 구현하면 됩니다.' 등으로 작성하지 않아야 하며, 예를 들어 '`if`-문을 사용하여 해결할 수 있습니다.' 등과 같이 도움이 될 만한 내용을 반드시 포함하여야 합니다. 21 | - 에디토리얼은, 다만, 해당 문제에 도전하는 참가자들이 이미 모두 알고 있을 것으로 예상되는 사항들에 대한 설명을 자제하는 것을 권장합니다. 22 | - **예)** 문제 해결 과정에서 $\left\lceil K/N \right\rceil$을 정수 연산으로만 구해야 하는 경우, Bronze에서는 해당 수식을 정수로 계산하는 방법을 소개하는 것이 의미 있겠지만, Platinum에서는 해당 사실이 문제를 해결하는 데에 핵심적인 관찰이 아닌 이상 대부분의 참가자들이 이미 알고 있을 것으로 예상되므로, 해당 사실을 언급하지 않는 것이 좋습니다. 23 | 24 | > **Note** 25 | > '어떤 문제에 도전하는 참가자들'은, 거칠게는 해당 문제에 대해 유의미한 시간 동안 고민하여 50% 정도의 확률로 해결할 수 있을 것으로 보이는 실력대의 참가자들에 초점을 맞추는 것으로 합니다. 예를 들어 난이도 순으로 정렬된 대회에서 D번에 도전하는 참가자들은 C번을 해결하고 대회 중에 D번에 도전하여 해결하지 못했거나, D번을 해결하고 E번을 고민하다가 대회 종료 시점에 E번을 해결하지 못한 참가자들로 생각할 수 있겠습니다. 26 | 27 | ## 포매팅 28 | 29 | ### 알고리즘 이름 30 | 31 | 알고리즘 및 문제해결 방법의 이름은 solved.ac의 공식 명칭을 반영하는 것을 권장합니다. 32 | 33 | - 알고리즘의 약어 등이 해당 문제에 도전하는 참가자들 사이에 잘 알려져 있을 경우 약어를 사용하는 것도 괜찮습니다. 다만, 약어를 사용할 때에는 모든 글자를 대문자로 표기하여야 합니다. 34 | - 약어의 예) DP(다이나믹 프로그래밍), BFS(너비 우선 탐색), ETT(오일러 투어 트릭) 등 35 | - 참고: [solved.ac의 알고리즘 분류](https://solved.ac/problems/tags) 36 | 37 | ### 수와 기호 38 | 39 | 작성 과정에서 아래를 참고할 수 있습니다. 40 | 41 | | 올바른 포매팅 | 잘못된 포매팅 | 42 | | ------------------------------------- | ------------------------------------- | 43 | | $7$일이 지난 후
`$7$일이 지난 후` | 7일이 지난 후
`7일이 지난 후` | 44 | | `Code`
`` `Code` `` | $\texttt{Code}$
`$\texttt{Code}$` | 45 | | **Bold**
`**Bold**` | $\textbf{Bold}$
`$\textbf{Bold}$` | 46 | 47 | ### TeX 48 | 49 | - 인라인 수식에서 `\displaystyle`, `\dfrac` 등을 사용하지 말아야 합니다. 수식이 길다면 블록 수식으로 작성하는 것을 고려합니다. 50 | - 블록 수식, 즉 글 사이에서 가운데 정렬되어 표시되는 수식은 아래와 같이 작성해야 합니다. 줄바꿈 위치에 주의합니다. 51 | 52 | $$ 53 | \frac{-b\pm\sqrt{b^2-4ac}}{2a} 54 | $$ 55 | 56 | ```tex 57 | $$ 58 | \frac{-b\pm\sqrt{b^2-4ac}}{2a} 59 | $$ 60 | ``` 61 | 62 | 블록 수식과 인라인 수식에 상관없이 작성 과정에서 아래를 참고할 수 있습니다. 63 | 64 | | 올바른 포매팅 | 잘못된 포매팅 | 65 | | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | 66 | | $\mathcal{O}(N^2)$
`\mathcal{O}(N^2)` | $O(N^2)$
`O(N^2)` | 67 | | $\mathcal{O}(N \log N)$
`\mathcal{O}(N \log N)` | $O(N log N)$
`O(N log N)` | 68 | | $\displaystyle\left\lfloor\frac{N}{2}\right\rfloor$
`\left\lfloor\frac{N}{2}\right\rfloor` | $\displaystyle \lfloor \frac{N}{2} \rfloor$
`\lfloor \frac{N}{2} \rfloor` | 69 | | $\displaystyle\left(1+\frac{1}{2}+2\right)$
`\left(1+\frac{1}{2}+2\right)` | $\displaystyle (1+\frac{1}{2}+2)$
`(1+\frac{1}{2}+2)` | 70 | | $A \times B$
`A \times B` | $A*B$
`A*B` | 71 | | $A \le B$
`A \le B` | $A<=B$
`A<=B` | 72 | | $\max \{1,2,3\}$
`\max \{1,2,3\}` | $max \{1,2,3\}$
`max \{1,2,3\}` | 73 | 74 | ## TeX(beamer)에서 마크다운으로 옮길 때에 주의할 점 75 | 76 | TeX는 마크다운으로 거의 그대로 옮길 수 있으나, 주의해야 할 점이 몇 가지 있습니다. 77 | 78 | - Math mode가 아닌 곳에서 `\textbf{bold}`는 `**bold**`로, `\textit{italic}`은 `*italic*`으로, `\texttt{monospace}`는 `` `monospace` ``로 옮겨야 합니다. 79 | - `itemize` 내의 여러 아이템은 하나의 문단으로 합치는 것을 권장합니다. 80 | - Math mode 문법 중 `\( ... \)` 및 `\[ ... \]`는 각각 `$ ... $` 및 `$$\n ... \n$$`으로 바꿔야 합니다. 81 | 82 | ## typst에서 마크다운으로 옮길 때에 주의할 점 83 | 84 | typst를 마크다운으로 옮길 때에는 다음을 주의해야 합니다. 85 | 86 | - typst의 `*Bold*`는 마크다운의 `**Bold**`로 옮겨야 합니다. 87 | 88 | 특히 수식의 문법이 다르므로, 옮길 때에는 각별한 주의가 필요합니다. 89 | 90 | | 의도한 TeX | 잘못 렌더되는 TeX | 91 | | ---------- | ----------------- | 92 | | $10^{100}$
`10^{100}` | $10^100$
`10^100` | 93 | | $A_{ij}$
`A_{ij}` | $A_(i j)$
`A_(i j)` | 94 | | $1 \le N$
`1 \le N` | $1 <= N$
`1 <= N` | 95 | | $u \rightarrow v$
`u \rightarrow v` | $u -> v$
`u -> v` | 96 | | $\Delta t$
`\Delta t` | $Delta t$
`Delta t` | 97 | | $\max \{a, b\}$
`\max \{a, b\}` | $max {a, b}$
`max {a, b}` | 98 | -------------------------------------------------------------------------------- /pre-contest/description/README.md: -------------------------------------------------------------------------------- 1 | # 디스크립션 2 | 3 | > 요약 4 | > 5 | > - 디스크립션은 명료해야 합니다. 6 | > - 문장을 짧고 간결하게 작성하는 것을 권장합니다. 7 | > - 디스크립션은 맞춤법을 지켜야 합니다. 8 | > - [한국어 맞춤법/문법 검사기](http://speller.cs.pusan.ac.kr/)의 도움을 받을 수 있습니다. 9 | > - 디스크립션은 문제를 푸는 사람이 이해할 수 있는 언어로 작성되어야 합니다(표현, 수학 기호 등). 10 | > - 디스크립션은 잘 포매팅되어 있어야 합니다. 11 | > - 대회 내의 문제들 간에 디스크립션이 일관되어야 합니다. 12 | 13 | 이하 모든 내용은 **디스크립션을 수정할 때마다 점검**해야 합니다. 14 | 15 | ## 목차 16 | 17 | - [목차](#목차) 18 | - [가독성과 명료성](#가독성과-명료성) 19 | - [맞춤법](#맞춤법) 20 | - [언어의 사회성](#언어의-사회성) 21 | - [문장과 문체](#문장과-문체) 22 | - [기호](#기호) 23 | - [입출력 형식](#입출력-형식) 24 | - [마크업](#마크업) 25 | - [일관성](#일관성) 26 | - [자주 사용되는 표현](#자주-사용되는-표현) 27 | 28 | ## 가독성과 명료성 29 | 30 | 디스크립션은 명료해야 합니다. 31 | 32 | - **(짧고 간결)** (UCPC 가이드라인) 디스크립션의 모든 문장을 짧고 간결하게 작성하는 것을 권장합니다. 33 | - **(난해하지 않게)** 참가자의 독해를 일부러 어렵게 하려는 장치는 없어야 합니다. 34 | - 문제의 상황 설명을 위한 스토리 등은 '독해를 일부러 어렵게 하는 장치'로 보지 않습니다. 다만, 이 경우에도 문제의 상황 설명은 독해하기 어렵지 않아야 합니다. 35 | - 디스크립션은 엄밀한 정의를 제공하기보다 이해하기 쉬운 정의를 제공하는 것을 목표해야 합니다. 36 | - **(문단)** 문단은 적절한 수의 문장으로 구성되어야 합니다. 37 | - 연관성이 높은 문장들을 하나의 문단으로 묶는 것을 권장합니다. 38 | - 연관성이 떨어지는 문장들은 다른 문단으로 분리하는 것을 권장합니다. 39 | - **(일관성)** 단어의 사용은 디스크립션 내에서 일관적이어야 합니다. 40 | - **예)** 한 문제의 디스크립션 내에서 충분한 설명 없이 '길', '도로', '간선' 또는 '시간', '비용' 등을 혼용하지 않습니다. 41 | 42 | ## 맞춤법 43 | 44 | (UCPC 가이드라인) 모든 디스크립션은 맞춤법을 지켜야 합니다. 45 | 46 | - 부산대학교 한국어 맞춤법/문법 검사기를 사용하는 것을 권장합니다. 다만, 기계 맞춤법 검사기는 올바르지 않은 개선사항을 제안할 수 있으니 개선사항을 무분별하게 수용하지 않습니다. (참고: [한국어 맞춤법/문법 검사기](http://speller.cs.pusan.ac.kr/)) 47 | - 극히 예외적인 상황에서 일부러 맞춤법을 어기려는 컨셉의 문제에서는 그렇게 하지 않아도 됩니다. 또한, 맞춤법을 지키지 않는 표현이 맞춤법을 지키는 표현보다 매우 널리 사용되는 경우에도 맞춤법을 지키지 않아도 됩니다. 48 | 49 | 또한 수식은 같은 의미의 문장으로 취급해야 합니다. 50 | 51 | - 문장이 수식으로 끝나는 경우 수식에도 마침표를 붙여야 합니다. 52 | - **예)** 53 | > - $f_1=1$. 54 | > - $f_2=2$. 55 | > - $n\ge 3$일 때, $f_n=f_{n-1}+f_{n-2}$. 56 | 57 | 특히, 자주 틀리는 사례들에 대해 주의해야 합니다. 58 | 59 | | 올바른 표현 | 잘못된 표현 | | 올바른 표현 | 잘못된 표현 | 60 | | -------------- | -------------- | --- | ------------ | ------------- | 61 | | 수\* | 숫자\* | | 개수 | 갯수 | 62 | | 최댓값, 최솟값 | 최대값, 최소값 | | 소숫점 | 소수점 | 63 | | 자릿수\*\* | 자리수\*\* | | 꼭짓점 | 꼭지점 | 64 | | 첫 번째 | 첫번째 | | 첫째 | 첫 째 | 65 | | 한 개 | 한개 | | ~한다(설명). | ~한다. (설명) | 66 | | "word." | "word". | | "word," | "word", | 67 | | A, B, and C | A, B, C | | | | 68 | 69 | - \* '숫자'는 수를 글자로서 취급할 때에만 사용합니다. 수를 값으로서 취급할 때에는 '수'를 사용합니다. 70 | - \*\* 맥락에 따라 '자리 수'도 올바른 표현일 수 있습니다 - '$4$자리 수' 등. 71 | 72 | ## 언어의 사회성 73 | 74 | 디스크립션은 문제를 푸는 사람이 이해할 수 있는 언어로 작성되어야 합니다. 75 | 76 | - **(은어)** 알고리즘 문제해결 커뮤니티 외, 특정 집단에서만 이해할 수 있는 표현 등은 충분한 설명 없이는 사용하지 않습니다. 77 | - **(수학 기호)** 수학 기호의 사용은 해당 문제와 비슷한 난이도의 문제를 주로 해결하는 사람들을 고려해야 합니다. 78 | - 수학 기호로 표현하는 것이 일반적인 문제해결자들의 입장에서 가독성을 해치지 않으면서, 표현하고자 하는 바를 더 간단하고 명료하게 표현할 수 있는 것이 아닌 이상, 수학 기호를 사용하지 않는 것을 권장합니다. 79 | - 특히, Gold 이하로 기획한 문제들에서는 수학 기호를 최대한 피하고, 피할 수 없는 경우에는 충분한 설명을 제공하는 것을 권장합니다. 80 | - **(사회적 합의 실패)** 사회적인 합의에 이르지 못한 단어는 사용하지 않습니다. 81 | - **예)** '자연수'의 정의는 분야에 따라 다르므로, 경우에 따라 '양의 정수', 혹은 '음이 아닌 정수' 등을 사용합니다. 82 | - **(유해한 내용)** (BOJ 가이드라인) 차별, 혐오, 또는 그를 함의하는 내용 등이 담긴 디스크립션은 작성하지 말아야 합니다. 83 | - 지식과 독해력 이외의 요소에 의해 문제해결 경험에 차이를 만드는 것은 불합리합니다. 84 | 85 | ## 문장과 문체 86 | 87 | - **(괄호)** (BOJ 가이드라인) 디스크립션에서 괄호는 사용하지 않을 수 있는 한 사용하지 않습니다. 88 | - **(번역체)** (BOJ 가이드라인) 번역체는 사용하지 않는 것이 좋습니다. 89 | - **예)** 입력으로 주어지는 데이터는 문제의 조건을 만족하고 있음이 보장된다. → 입력으로 주어지는 데이터는 문제의 조건을 만족한다. 90 | 91 | ## 기호 92 | 93 | - **(제한의 등장 위치)** 입력부에서 사용하는 기호의 제한은 디스크립션이 아니라 입력부에서 제공하는 것을 권장합니다. 94 | - **예)** [GA1 E](https://www.acmicpc.net/problem/28435) 95 | > (문제) 크기 $N$인 집합 $A = \{A_1, A_2, \cdots, A_N\}$와 정수 $K$가 주어집니다. 96 | > 97 | > (입력) 첫 줄에 정수의 개수 $N$과 문제의 정수 $K$가 공백으로 구분되어 주어집니다. $(2 \le N, K \le 100\,000)$ 98 | - **(재언급)** 디스크립션에서 기호를 정의했더라도, 입력부에서 그 정의를 다시 언급해 주는 것을 권장합니다. 99 | - **(비권장하는 예)** 100 | > (입력) 이후 $T$ 개의 줄에 각각 문제에서 언급한 정수 $N$이 한 줄에 하나씩 주어진다. 101 | - **(리터럴)** 배열의 경우 대괄호(`[]`)로, 집합 등의 경우 중괄호(`{}`)로, 튜플 및 벡터 등의 경우 소괄호(`()`)로 감싸 나타냅니다. 102 | - **예)** 배열 $[3, 1, 4, 1]$에 대한 답은 $5$다. 103 | 104 | ## 입출력 형식 105 | 106 | - **(명확한 입출력 형식 정의)** (UCPC 가이드라인) 입출력 형식은 명확하게 정의되어야 합니다. 아래 목록의 사항들을 지문에 나타낼 수 있으면 나타내야 합니다. 107 | - 기호들이 공백으로 구분되어 표현됨 108 | - 기호가 정수로 표현됨 109 | - 기호가 소수점 아래 최대 $N$자리까지의 실수로 표현됨 110 | - **(이해하기 쉬운 입력 형식)** 입력 형식을 설명한 글은 최대한 실제 입력 순서와 일치하는 순서로 입력을 설명해야 합니다. 111 | - 입력 파일에서 한 줄에 들어오는 기호들은 입력 형식 설명에서 한 문단 내에 표현하여야 합니다. 112 | - 입력 파일의 여러 줄에 대한 설명을 입력 형식 성명에서 한 문단으로 하지 않아야 합니다. 113 | - 입력 파일에서 기호들이 들어오는 순서대로 입력 형식 설명에서 해당 기호들을 언급하여야 합니다. 114 | - **안 좋은 예)** 입력은 $N$, $M$, $K$ 순서대로 들어오지만, 입력 설명에서 $K$에 대하여 먼저 설명하는 경우 등 115 | 116 | ## 마크업 117 | 118 | 모든 문제의 마크업은 인라인 LaTeX를 사용합니다. 119 | 120 | - **(Well-formed)** (BOJ 가이드라인) 문제 디스크립션은 BOJ의 '문제 안내'를 따릅니다. (참고: [BOJ Help: 문제 안내](https://stack.acmicpc.net/guide/problem)) 121 | - **(수식)** (UCPC 가이드라인) 모든 변수와 기수 등은 math mode로 작성해야 합니다. 서수는 text mode로 작성해도 됩니다. Math mode 수식 작성 방법은 UCPC 가이드라인을 따릅니다. 122 | - **(강조)** 디스크립션에서 처음으로 등장하는 개념 등을 적당히 강조합니다. 다만, 해당 디스크립션에서 해당 단어가 등장하는 첫 위치에만 강조하는 것을 권장합니다. 123 | 124 | - **[예)](https://www.acmicpc.net/problem/28435)** (GA1 E) 125 | 126 | > $A$의 부분집합 $S$가 **좋은 집합**이라는 것은 다음 조건을 모두 만족시킴을 의미합니다. 127 | 128 | > A subset $S$ of $A$ is called a **good set** if it satisfies all of the following conditions. 129 | 130 | - **(리터럴)** (UCPC 가이드라인) 입력 설명에서, 정확히 어떤 문자열을 입력 또는 출력해야 하는 경우에는 붉은 고정폭 글씨로 강조합니다. 131 | - 강조를 위한 색상은 #e74c3c를 사용합니다. 이 색상은 BOJ Stack에서 '창백한 빨강'입니다. 132 | ![BOJ Stack 색상 선택기](./image-1.png?raw=true) 133 | - **[예)](https://www.acmicpc.net/problem/28436)** (GA1 F) 134 | > 흰색 팀이 이긴다면 “WHITE”, 검은색 팀이 이긴다면 “BLACK”을 출력하세요. 135 | 136 | ## 일관성 137 | 138 | 대회 내의 문제들 간에 디스크립션이 일관되어야 합니다. 139 | 140 | - **(문체)** 대회 내의 모든 문제들은 같은 문체로 작성되어야 합니다. 141 | - **(표현)** 대회 내에서 처음 등장한 표현 등은 서로 다른 문제에서 다른 의미로 정의하는 것을 피하는 것을 권장합니다. 142 | - **(배경 설정 등)** 대회 내에서 등장한 등장인물과 배경 등의 설정은 서로 다른 문제에서 다르게 소개하는 것을 피하는 것을 권장합니다. 143 | 144 |
145 | 일관성이 떨어지는 예시 146 | 147 | - 어떤 문제는 존댓말을, 어떤 문제는 반말을 사용함. 148 | - '좋은 집합'의 정의가 문제에 따라 다름. 149 | 150 |
151 | 152 |
153 | 그랜드 아레나 문체 예시 154 | 155 | 합의할 문체를 찾지 못했다면 그랜드 아레나의 문체를 사용하는 것도 괜찮습니다. 156 | 157 | - 경어를 사용합니다. 모든 문장은 존댓말로 작성합니다. 158 | - (문제) '(답을) 구하세요.' / '(답을) 출력합니다.' / '(답이) 무엇일까요?' / '(조건을 만족하도록) 할 수 있나요?' 159 | - (입력) '(입력 또는 변수가) 주어집니다.' 160 | - (출력) '(답 또는 값을) 출력하세요.' 161 | - (예제 설명) '(예제를) 출력합니다.' 162 | 163 |
164 | 165 | ## 자주 사용되는 표현 166 | 167 | 필요한 경우 [자주 사용되는 표현](expressions.md) 문서에서 표현을 복사하여 사용해도 괜찮습니다. (TODO) 168 | -------------------------------------------------------------------------------- /appendix/testlib/random_t.md: -------------------------------------------------------------------------------- 1 | # random_t 2 | 3 | - 해당 내용: **Generator** 4 | 5 | ## 목차 6 | 7 | - [목차](#목차) 8 | - [일반](#일반) 9 | - [rnd](#rnd) 10 | - [random\_t::setSeed](#random_tsetseed) 11 | - [무작위 생성](#무작위-생성) 12 | - [random\_t::next(std::string)](#random_tnextstdstring) 13 | - [random\_t::next(integer)](#random_tnextinteger) 14 | - [random\_t::next(integer, integer)](#random_tnextinteger-integer) 15 | - [random\_t::next()](#random_tnext) 16 | - [random\_t::next(double)](#random_tnextdouble) 17 | - [random\_t::next(double, double)](#random_tnextdouble-double) 18 | - [random\_t::any](#random_tany) 19 | - [가중 무작위 생성](#가중-무작위-생성) 20 | - [random\_t::wnext(type)](#random_twnexttype) 21 | - [random\_t::wnext(double, type)](#random_twnextdouble-type) 22 | - [random\_t::wnext(integer, type)](#random_twnextinteger-type) 23 | - [random\_t::wnext(integer, integer, type)](#random_twnextinteger-integer-type) 24 | - [random\_t::wany](#random_twany) 25 | - [배열 생성](#배열-생성) 26 | - [random\_t::perm](#random_tperm) 27 | - [random\_t::distinct](#random_tdistinct) 28 | - [random\_t::partition](#random_tpartition) 29 | - [전역 유틸리티 메서드](#전역-유틸리티-메서드) 30 | - [shuffle](#shuffle) 31 | 32 | ## 일반 33 | 34 | ### rnd 35 | 36 | - `random_t rnd` 37 | 38 | `rnd`는 `random_t`의 인스턴스로, 전역 변수입니다. 39 | 40 | `rnd`의 랜덤 시드는 `registerGen` 시에 결정되며, 커맨드 라인 변수 `argc`와 `argv`를 기반으로 계산됩니다. 즉, 커맨드 라인 변수가 같다면 랜덤의 결과도 항상 같습니다. 41 | 42 | 문제의 정해를 테스트할 때, 테스트를 생성할 때마다 랜덤 시드가 바뀐다면 stress test 등으로 발견한 예외 케이스가 유실될 수 있습니다. `random_t`를 사용하면 테스트 케이스 생성기를 여러 번 실행해도 같은 테스트 케이스를 생성해 주므로 이런 문제를 방지할 수 있습니다. 43 | 44 | 제네레이터를 작성할 때에는 이런 이유로 `std::rand`, `std::random_shuffle`과 `std::srand`를 사용하지 않고, 전역 변수 `rnd`를 통해 무작위 값을 생성해야 합니다. 45 | 46 | ### random_t::setSeed 47 | 48 | - `void setSeed(long long _seed)` 49 | - `_seed`: 랜덤 시드. 50 | 51 | `random_t`의 시드를 설정합니다. 일반적인 경우 시드는 자동으로 결정되므로 이 메서드를 사용할 일은 없습니다. 52 | 53 | ## 무작위 생성 54 | 55 | ### random_t::next(std::string) 56 | 57 | - `std::string next(const std::string &ptrn)` 58 | - `std::string next(const char *format, ...)` 59 | - `ptrn`: 정규 표현식. 60 | - `format`, `...`: 정규 표현식을 생성하는 `printf` 스타일의 포맷 문자열 및 가변 인자. 61 | 62 | `ptrn`을 만족하는 문자열을 무작위 생성합니다. `ptrn`은 [pattern](./pattern.md) 표현식을 만족하는 문자열이어야 합니다. 63 | 64 | `ptrn`은 0회 이상 반복을 나타내는 문자 `*`를 포함하면 안 됩니다. `ptrn`에 어떤 문자를 제외하고 나머지를 허용하는 문법 `[^...]`이 등장할 경우 제대로 실행됨을 보장하지 않습니다. 65 | 66 | `next`는 포맷 스트링을 직접 지원합니다. 즉, `next(format("[ABC]{%d}", n))` 대신 `next("[ABC]{%d}", n)`와 같이 작성 가능합니다. 67 | 68 | ### random_t::next(integer) 69 | 70 | - `int next(int n)` 71 | - `unsigned int next(unsigned int n)` 72 | - `long long next(long long n)` 73 | - `unsigned long long next(unsigned long long n)` 74 | - `long next(long n)` 75 | - `unsigned long next(unsigned long n)` 76 | - `n`: 생성 범위를 나타내는 정수. 77 | 78 | $\left[0,n\right)$ 범위의 정수를 무작위로 생성합니다. `n`은 양의 정수여야 합니다. 79 | 80 | ### random_t::next(integer, integer) 81 | 82 | - `int next(int from, int to)` 83 | - `unsigned int next(unsigned int from, unsigned int to)` 84 | - `long long next(long long from, long long to)` 85 | - `unsigned long long next(unsigned long long from, unsigned long long to)` 86 | - `long next(long from, long to)` 87 | - `unsigned long next(unsigned long from, unsigned long to)` 88 | - `from`, `to`: 생성 범위를 나타내는 정수. 89 | 90 | $\left[\texttt{from},\texttt{to}\right]$ 범위의 정수를 무작위로 생성합니다. 값 `to`도 생성될 수 있음에 주의합니다. $\texttt{from} < \texttt{to}$여야 합니다. 91 | 92 | ### random_t::next() 93 | 94 | - `double next()` 95 | 96 | $\left[0, 1\right)$ 사이의 실수를 무작위로 생성합니다. 97 | 98 | ### random_t::next(double) 99 | 100 | - `double next(double n)` 101 | - `n`: 생성 범위를 나타내는 실수. 102 | 103 | $\left[0, n\right)$ 사이의 실수를 무작위로 생성합니다. $n>0$이어야 합니다. 104 | 105 | ### random_t::next(double, double) 106 | 107 | - `double next(double from, double to)` 108 | - `from`, `to`: 생성 범위를 나타내는 실수. 109 | 110 | $\left[\texttt{from},\texttt{to}\right]$ 범위의 실수를 무작위로 생성합니다. $\texttt{from} < \texttt{to}$여야 합니다. 111 | 112 | ### random_t::any 113 | 114 | - `template typename Container::value_type any(const Container &c)` 115 | - `template typename Iter::value_type any(const Iter &begin, const Iter &end)` 116 | - `Container`: 컨테이너 타입. 117 | - `Iter`: 반복자 타입. 118 | - `c`: 컨테이너. 119 | - `begin`, `end`: 반복자. 120 | 121 | `c`, 혹은 $\left[\texttt{begin}, \texttt{end}\right)$로 정의된 구간 내의 원소 중 하나를 무작위로 선택합니다. 122 | 123 | ## 가중 무작위 생성 124 | 125 | 아래 모든 함수는 `next` 메서드와 비슷한 동작을 가지나, 인자 `type`의 값에 따라 조금씩 다른 동작을 보입니다. 126 | 127 | - $\texttt{type}=0$이라면, 이 메서드는 `next(...)`과 동작이 같습니다. 128 | - $\texttt{type}>0$이라면, 이 메서드는 `next(...)`을 `type` 번 호출하여, 그 중 가장 큰 값을 반환합니다. 129 | - $\texttt{type}<0$이라면, 이 메서드는 `next(...)`을 `-type` 번 호출하여, 그 중 가장 작은 값을 반환합니다. 130 | 131 | ### random_t::wnext(type) 132 | 133 | - `double wnext(int type)` 134 | - `type`: 생성 방식을 나타내는 정수. 135 | 136 | $\left[0, 1\right)$ 사이의 실수를 생성합니다. 137 | 138 | ### random_t::wnext(double, type) 139 | 140 | - `double wnext(double n, int type)` 141 | - `n`: 생성 범위를 나타내는 실수. 142 | - `type`: 생성 방식을 나타내는 정수. 143 | 144 | $\left[0, n\right)$ 사이의 실수를 생성합니다. $n>0$이어야 합니다. 145 | 146 | ### random_t::wnext(integer, type) 147 | 148 | - `int wnext(int n, int type)` 149 | - `unsigned int wnext(unsigned int n, int type)` 150 | - `long long wnext(long long n, int type)` 151 | - `unsigned long long wnext(unsigned long long n, int type)` 152 | - `long wnext(long n, int type)` 153 | - `unsigned long wnext(unsigned long n, int type)` 154 | - `n`: 생성 범위를 나타내는 정수. 155 | - `type`: 생성 방식을 나타내는 정수. 156 | 157 | $\left[0,n\right)$ 범위의 정수를 생성합니다. `n`은 양의 정수여야 합니다. 158 | 159 | ### random_t::wnext(integer, integer, type) 160 | 161 | - `int wnext(int from, int to, int type)` 162 | - `unsigned int wnext(unsigned int from, unsigned int to, int type)` 163 | - `long long wnext(long long from, long long to, int type)` 164 | - `unsigned long long wnext(unsigned long long from, unsigned long long to, int type)` 165 | - `long wnext(long from, long to, int type)` 166 | - `unsigned long wnext(unsigned long from, unsigned long to, int type)` 167 | - `from`, `to`: 생성 범위를 나타내는 정수. 168 | 169 | $\left[\texttt{from},\texttt{to}\right]$ 범위의 정수를 생성합니다. 값 `to`도 생성될 수 있음에 주의합니다. $\texttt{from} < \texttt{to}$여야 합니다. 170 | 171 | ### random_t::wany 172 | 173 | - `template typename Container::value_type wany(const Container &c, int type)` 174 | - `template typename Iter::value_type wany(const Iter &begin, const Iter &end, int type)` 175 | - `Container`: 컨테이너 타입. 176 | - `Iter`: 반복자 타입. 177 | - `c`: 컨테이너. 178 | - `begin`, `end`: 반복자. 179 | - `type`: 생성 방식을 나타내는 정수. 180 | 181 | `c`, 혹은 $\left[\texttt{begin}, \texttt{end}\right)$로 정의된 구간 내의 원소 중 하나를 선택합니다. 182 | 183 | `type`가 0이 아닌 경우, 이 함수는 인덱스를 `wnext(c.size(), type)`로 고르고, 그 인덱스에 해당하는 원소를 반환합니다. $|\texttt{type}|$ 번 원소를 고르고 그 중 최대/최솟값을 고르는 것이 아님에 주의합니다. 184 | 185 | ## 배열 생성 186 | 187 | ### random_t::perm 188 | 189 | - `template std::vector perm(T size)` 190 | - `template std::vector perm(T size, E first)` 191 | - `T`: 생성할 배열의 크기를 나타내는 정수 타입. 192 | - `E`: 생성할 배열의 원소를 나타내는 정수 타입. 193 | - `size`: 생성할 배열의 크기. 194 | - `first`: 생성할 배열의 원소의 최솟값. 195 | 196 | 서로 다른 `size`개의 연속한 수가 무작위 순서로 들어 있는 배열을 생성합니다. `first`가 주어지면, 배열의 원소는 $\left[\texttt{first}, \texttt{first}+\texttt{size}\right)$ 내의 정수를 모두 포함합니다. `first`가 주어지지 않는다면, 배열의 원소는 $\left[0, \texttt{size}\right)$ 내의 정수를 모두 포함합니다. 197 | 198 | ### random_t::distinct 199 | 200 | - `template std::vector distinct(int size, T from, T to)` 201 | - `template std::vector distinct(int size, T upper)` 202 | - `T`: 생성할 배열의 원소를 나타내는 정수 타입. 203 | - `from`, `to`: 생성할 배열의 원소의 범위. 204 | - `upper`: 생성할 배열의 원소의 최댓값. 205 | 206 | 주어진 구간 내에서 서로 다른 `size`개의 정수가 들어 있는 배열을 생성합니다. `from`과 `to`가 주어지면, 배열의 원소는 $\left[\texttt{from}, \texttt{to}\right]$ 사이에서 무작위로 생성됩니다. 그렇지 않다면, 배열의 원소는 $\left[0, \texttt{upper}\right)$ 사이에서 무작위로 생성됩니다. 207 | 208 | $\texttt{from} < \texttt{to}$; $0 \le \texttt{size} \le \texttt{to}-\texttt{from}+1 \le 10^9$여야 합니다. $\texttt{upper}>0$, $0\le \texttt{size} \le \texttt{upper}$여야 합니다. 209 | 210 | ### random_t::partition 211 | 212 | - `template std::vector partition(int size, T sum)` 213 | - `template std::vector partition(int size, T sum, T min_part)` 214 | - `T`: 생성할 배열의 원소를 나타내는 정수 타입. 215 | - `size`: 생성할 배열의 크기. 216 | - `sum`: 생성할 배열의 원소의 합. 217 | - `min_part`: 생성할 배열의 원소의 최솟값. 218 | 219 | 최솟값이 `min_part`이고, 합이 `sum`이 되는 `size`개의 정수가 들어 있는 배열을 생성합니다. `min_part`가 주어지지 않으면, 최솟값은 1입니다. 220 | 221 | $\texttt{size} \ge 0$이어야 합니다. $\texttt{size}=0$이라면, $\texttt{sum}=0$이어야 합니다. $\texttt{min\\\_part}\times\texttt{size}\le\texttt{sum}$이어야 합니다. 222 | 223 | ## 전역 유틸리티 메서드 224 | 225 | ### shuffle 226 | 227 | - `template void shuffle(_RandomAccessIter __first, _RandomAccessIter __last)` 228 | - `_RandomAccessIter`: 랜덤 액세스 반복자 타입. 229 | - `__first`: 배열의 시작 반복자. 230 | - `__last`: 배열의 끝 반복자. 231 | 232 | 배열 $\left[\texttt{\\\_\\\_first}, \texttt{\\\_\\\_last}\right)$를 무작위 순서로 섞습니다. 233 | -------------------------------------------------------------------------------- /pre-contest/data/README.md: -------------------------------------------------------------------------------- 1 | # 데이터 및 채점 2 | 3 | > 요약 4 | > 5 | > - 채점이 밀리지 않도록 데이터의 크기를 조절해야 합니다. 6 | > - Polygon을 사용해 데이터를 작성해야 합니다. Polygon 패키지에 경고가 있어서는 안 됩니다. 7 | > - Validator와 Checker는 C 또는 C++로 작성해야 하며, 검수 및 실수 탐지의 용이성을 제1 목표로 작성해야 합니다. 8 | > - Validator에서 등장하는 수 및 기호는 지문의 것을 그대로 따라야 합니다. 9 | > - Validator와 Checker에는 `#define`을 사용하지 않아야 합니다. 10 | > - Checker는 맞는 소스를 틀리다고 판정할 가능성은 없는지 꼼꼼히 점검하면서 작성해야 합니다. 11 | > - 데이터는 충분히 강력해야 합니다. 12 | 13 | ## 출제 분야별 주의사항 14 | 15 | - 실수를 다루는 문제 (TODO: 오차 계산) 16 | - 기하학 (TODO: 정수로 계산하기; 세 점이 한 직선 위에 있는지 validation 등) 17 | - 이분 탐색, 매개 변수 탐색 (TODO: 범위에 주의하도록 함) 18 | - 데이크스트라 (TODO) 19 | - 플로우 (TODO: 틀린 팀노트) 20 | - 문자열, 해싱 (TODO: 소수 저격하지 않도록 함) 21 | - 무작위화 (TODO: 확률 계산) 22 | 23 | ## 목차 24 | 25 | - [출제 분야별 주의사항](#출제-분야별-주의사항) 26 | - [목차](#목차) 27 | - [데이터의 크기](#데이터의-크기) 28 | - [데이터의 개수](#데이터의-개수) 29 | - [참가 하한 Unrated에서](#참가-하한-unrated에서) 30 | - [Polygon](#polygon) 31 | - [공통](#공통) 32 | - [테스트 작성](#테스트-작성) 33 | - [Generator 작성](#generator-작성) 34 | - [Validator 작성](#validator-작성) 35 | - [Checker 작성](#checker-작성) 36 | - [데이터의 강력함](#데이터의-강력함) 37 | - [점검 사항](#점검-사항) 38 | 39 | ## 데이터의 크기 40 | 41 | 데이터의 총 용량은 1GB를 넘지 않도록 합니다. 42 | 43 | > [!Note] 44 | > 데이터의 총 용량은 BOJ에서 '채점 준비 중'이 표시되는 시간과 관련이 있습니다. BOJ에서 1GB의 데이터를 처리하는 데에는 경험적으로 ~5초가 소요되는 것으로 알려져 있습니다. 45 | 46 | ## 데이터의 개수 47 | 48 | 데이터의 수 곱하기 시간 제한(# × TL)은 아래 제한을 따릅니다. 49 | 50 | | 예상 난이도 | # × TL | 51 | | ------------- | ------------ | 52 | | Bronze | ≤ 30초 | 53 | | Silver | ≤ 90초 | 54 | | Gold | ≤ 5분 | 55 | | ≥ Platinum | ≤ 15분 | 56 | 57 | > [!Note] 58 | > \# × TL이 커질수록 제출 하나의 채점에 걸리는 시간이 늘어나며, 채점 큐가 밀릴 가능성이 있습니다. 59 | 60 | ### 참가 하한 Unrated에서 61 | 62 | 특히, 참가 제한이 Unrated부터인 대회에서, 가장 많은 참가자가 해결할 것으로 예상하는 문제에 대하여 아래의 추가 제한을 따릅니다. 63 | 64 | | 예상 난이도 | # × TL | 65 | | ----------- | ------------ | 66 | | 가장 쉬움 | ≤ 10초 | 67 | 68 | ## Polygon 69 | 70 | Generator, validator, checker 및 interactor 준비에는 Codeforces의 [Polygon 플랫폼](https://polygon.codeforces.com/)과 `testlib.h`를 사용해야 합니다. 71 | 72 | - 참고: [Codeforces: Briefly about testlib.h](https://codeforces.com/testlib) 73 | - 참고: [Codeforces: Generators with testlib.h](https://codeforces.com/blog/entry/18291) 74 | - 참고: [Codeforces: Validators with testlib.h](https://codeforces.com/blog/entry/18426) 75 | - 참고: [Codeforces: Interactors with testlib.h](https://codeforces.com/blog/entry/18455) 76 | - 참고: [Codeforces: Checkers with testlib.h](https://codeforces.com/blog/entry/18431) 77 | 78 | ### 경고 해결 79 | 80 | Polygon 패키지에는 no tags, no statement 등을 포함한 모든 경고가 없어야 합니다. 단, 다음 예외를 허용합니다. 81 | 1. Solution '``' uses unusual int128-like type on the line `` 82 | 2. Lack `` in section `
` of `` statement 83 | 3. Lack cursive font substrings in section `
` of `` statement 84 | 85 | > [!Caution] 86 | > (2)번 경고의 경우 직접 꼼꼼하게 지문을 확인하여야 합니다. 87 | 88 | ### 공통 89 | 90 | - **(간결한 소스 코드)** Polygon에 작성하는 모든 코드는 검수에 용이하도록 매크로 등을 사용하지 말고 최대한 간결하게 작성합니다. 91 | - 매크로 및 템플릿의 사용은 다른 검수자가 이를 이해하는 데에 어려움을 주고, 검수 미비로 이어질 가능성이 높기 때문에 지양되어야 합니다. 92 | - 복잡한 로직은 최대한 많은 함수로 쪼갭니다. 93 | - 함수의 인자로 6개 이상의 변수를 받지 않으며, 필요한 경우 `struct` 등을 정의하여 사용합니다. 94 | - **(외부 소스 코드)** 이미 구현체가 있는 알고리즘(플로우, FFT 등)의 소스를 사용하고자 하는 경우, 해당 내용과 메인 코드를 주석으로 구분하고 출처를 명시합니다. 95 | - 저자 명시의 의미도 있지만, 간혹 기반 구현체를 믿을 수 없는 경우도 있기 때문입니다. 96 | 97 | 이하의 내용이 경고를 해결하는 데에 도움이 될 수 있습니다. 98 | 99 | ### 테스트 작성 100 | 101 | - 직접 생성한 데이터의 등록은 다음 경우를 제외하고 지양하며, 꼭 직접 생성한 데이터를 등록해야 한다면, description 란에 생성 방법 등을 명확히 설명합니다. 102 | - 예제에 사용하는 데이터 103 | - 데이터의 생성에 너무 오랜 시간이 걸려 Polygon에서 생성 시간 제한을 초과하는 데이터 104 | - Validator에 정의한 변수에서, 최댓값을 만족하는 데이터와 최솟값을 만족하는 데이터가 각각 하나 이상 있어야 합니다. 현재 문제의 제한 상 그런 데이터를 작성할 수 없다면, 문제의 제한을 변경하거나 명확히 합니다. 105 | - **예)** 제한이 '정점의 개수 $N$과 간선의 개수 $M$에 대해 $1 \le N, M \le 10^5$'인 경우, $N=1$인 경우에 $M \le 0$이어야 하여 해당 데이터를 만들 수 없으므로, $N \ge 2$ 혹은 $M \ge 0$으로 수정. 106 | 107 | ### Generator 작성 108 | 109 | - 참고: [testlib.h 비공식 문서: Generator](/appendix/testlib/README.md#generator) 110 | - 참고: [Codeforces: Generators with testlib.h](https://codeforces.com/blog/entry/18291) 111 | 112 | - Multitest generator는 사용하면 안 됩니다. 113 | - 하나의 generator가 명확한 argument 없이 여러 전략의 데이터를 생성하면 안 됩니다. 114 | - Generator의 이름은 테스트 생성 전략을 설명하는 이름이어야 합니다. 의미 없는 이름을 정해서는 안 됩니다. 115 | - **나쁜 예)** `gen`, `gen_a`, `generator` 등 116 | - **좋은 예)** `genrand`, `genmax`, `gen_prime`, `gen_random_tree` 등 117 | - 길이는 길어도 상관없습니다. 118 | - Generator argument는 testlib의 `opt`를 사용하여 받는 것을 권장합니다. 119 | - **예)** `genrand -n 100 -m 540 -b 2 -t 0` 120 | ```cpp 121 | int n = opt("n"); 122 | int m = opt("m"); 123 | int b = opt("b"); 124 | int t = opt("t"); 125 | ``` 126 | - 참고: [testlib.h 비공식 문서: opt](/appendix/testlib/opt.md) 127 | 128 | ### Validator 작성 129 | 130 | - 참고: [testlib.h 비공식 문서: Validator](/appendix/testlib/README.md#validator) 131 | - 참고: [Codeforces: Validators with testlib.h](https://codeforces.com/blog/entry/18426) 132 | 133 | Validator는 문제 패키지에서 가장 실수가 발생하기 쉽고, 실수가 발생했을 때의 영향이 큰 곳 중 하나로, **검수 및 실수 탐지의 용이성을 제1 목표로 두고** 작성해야 합니다. 134 | 135 | - Validator는 C 혹은 C++로 작성해야 합니다. 136 | - Validator 코드에서는 `#define`을 사용하면 안 됩니다. 137 | - 타입 재정의를 사용하려는 경우, `using` 또는 `typedef`를 사용합니다. 138 | - **안 좋은 예 1)** 아래와 같은 매크로 사용은 코드를 큰 폭으로 바꾸지만 모두에게 익숙하지 않고, 이로 인해 코드 해석의 시간 및 실수 가능성이 증가될 수 있으므로 사용하면 안 됩니다. 139 | ```cpp 140 | #define rep(a, b) for (int i = (a); i < (b); i++) 141 | #define all(v) (v).begin(), (v).end() 142 | ``` 143 | - **안 좋은 예 2)** 아래와 같은 매크로는 이미 많은 사람이 학습한 기호를 재정의하여 혼선이 발생할 수 있으므로 사용하면 안 됩니다. 144 | ```cpp 145 | #define int long long 146 | ``` 147 | - **좋은 예)** 148 | ```cpp 149 | using ll = long long; 150 | ``` 151 | - Validator 코드에 수(특히 제한)를 적는 경우, 지문에 적은 대로 적습니다. 1,000 단위 구분 기호를 적극적으로 사용합니다(UCPC 가이드라인을 따르는 지문의 경우 지문에 이미 1,000 단위 구분 기호가 있을 것입니다). 152 | - **예 1)** $1 \le N \le 100\\,000$ → `inf.readInt(1, 100'000, "N")` 153 | - **예 2)** $1 \le N \le 10^9$ → `inf.readInt(1, 1e9, "N")` 154 | - `readInt`, `readWord` 등을 사용할 때 마지막 인자로 변수 이름을 지문에 적은 대로 적습니다. 155 | - **안 좋은 예 1)** $1 \le N \le 1\\,000$ → `inf.readInt(1, 1'000)` 156 | - **안 좋은 예 2)** $1 \le T \le 1\\,000$ → `inf.readInt(1, 1'000, "N")`: 번수명이 달라 검수 과정 중 헷갈릴 위험이 있습니다. 157 | - **안 좋은 예 3)** $1 \le N \le 1\\,000$ → `inf.readInt(1, 1'000, "n")`: 이후 문제 수정 과정 중에 casing이 다른 $n$ 등의 변수가 등장할 수 있으므로, 대소문자도 지문에 적은 대로 적는 것이 권장됩니다. 158 | - **좋은 예 1)** $1 \le N \le 1\\,000$ → `inf.readInt(1, 1'000, "N")` 159 | - **좋은 예 2)** $1 \le a_{ij} \le 10^6$ → `inf.readInt(1, 1e6, "a_ij")` 160 | - **좋은 예 3)** $1 \le a_{ij} \le 10^6$ → `inf.readInt(1, 1e6, format("a_(%d,%d)", i, j))` 161 | 162 | ### Checker 작성 163 | 164 | - 참고: [testlib.h 비공식 문서: Checker](/appendix/testlib/README.md#checker) 165 | - 참고: [Codeforces: Checkers with testlib.h](https://codeforces.com/blog/entry/18431) 166 | 167 | Checker도 실수의 영향이 굉장히 큰 곳입니다. 검수 및 실수 탐지의 용이성을 고려하여 작성하되, 맞는 소스를 틀리다고 판정할 가능성은 없는지 꼼꼼히 점검하면서 작성하는 것이 무엇보다 중요합니다. 168 | 169 | > [!Important] 170 | > 출력 형식이 중요한 문제가 아닐 경우 Checker에서 출력 형식을 검증해서는 안 됩니다. 본 매뉴얼은 일반적인 경우에서 `1 2 3`과 `1\n2\n3`을 같은 의미를 가지는 출력으로 보도록 하고 있습니다. 171 | > 172 | > BOJ는 기본적으로 줄 끝 공백을 허용하는 등 출력 형식에 엄격하지 않습니다. 이를 checker로 직접 구현하기는 다소 번거로우며, 보통 입출력 형식을 지키는 것 자체가 문제에서 물어보고자 하는 핵심 스킬인 경우는 드뭅니다. 따라서 아레나는 출력 형식 검증이 중요하지 않다고 보고 있습니다. 173 | 174 | - Checker는 C 혹은 C++로 작성해야 합니다. 175 | - Checker 코드에서는 `#define`을 사용하면 안 됩니다. 176 | - BOJ의 스페셜 저지 기능을 사용하지 않으려는 경우, Polygon에서 checker는 `wcmp.cpp`로 정합니다. 177 | - 참고: [BOJ Help: 채점 결과#출력 형식이 잘못되었습니다](https://help.acmicpc.net/judge/info) 178 | - Checker는 줄 끝 공백에 대하여 관대하여야 합니다. 179 | - **예 1)** 정답이 '`Impossible`'이라면, '`Impossible`'과 '`Impossible `' 모두 정답으로 처리해야 합니다. 180 | - **예 2)** 정답이 '`1 2 3`'이라면, '`1 2 3`'과 '`1 2 3 `' 모두 정답으로 처리해야 합니다. 181 | - 출력 형식이 중요한 문제가 아닐 경우, checker 내에서 다음 함수를 사용하지 않습니다. 182 | - `readEoln()` 183 | - `readEof()` 184 | - `readSpace()` 185 | - 참고: [testlib.h 비공식 문서: InStream/Strict Mode](/appendix/testlib/instream.md#strict-mode) 186 | - Checker는 참가자의 정답이 출제자의 정답보다 효율적인(정해가 틀리는) 사고가 발생할 가능성이 있음을 인지하고, [`_fail`](/appendix/testlib/tresult.md#_fail) 판정을 사용하여야 합니다. 187 | 188 | ## 데이터의 강력함 189 | 190 | 채점 데이터는 충분히 강력해야 하며, 의도하지 않은 풀이로 해결할 수 있는 경우를 최대한 방지하기 위해 여러 전략의 generator를 작성할 것을 권장합니다. 더 자세한 내용은 [풀이 및 제한 설정](/pre-contest/solution/README.md) 문서를 참고합니다. 191 | 192 | 다음 기계적으로 점검할 수 있는 사항들을 점검하고, 해당 데이터가 없다면 추가합니다. 193 | 194 | - 기호의 입력 범위의 최소 또는 최댓값을 포함하는 입력 데이터가 있는가? 195 | - **예)** $1 \le N \le 100\,000$이라면 $N = 1$인 데이터와 $N = 100\,000$인 데이터가 하나 이상씩 있는지 점검합니다. 196 | - 최선의 경우와 최악의 경우, 또는 그에 준하는 입력 데이터가 있는가? 197 | - **예)** 이분 탐색을 정해로 하는 문제에서 가능한 답 $X$의 범위가 $0 \le X \le 10\,000$일 때, $X = 0$인 데이터와 $X = 10\,000$인 데이터가 하나 이상씩 있는지 점검합니다. 198 | 199 | 데이터를 강력하게 만들기 위해 Polygon의 stress test를 활용할 수 있습니다. 200 | 201 | ## 점검 사항 202 | 203 | 다음 방법으로 문제가 훨씬 쉽게 해결될 여지가 있는지 점검합니다. 204 | 205 | - [OEIS?](https://oeis.org/) 206 | - [Inverse Symbolic Calculator?](https://wayback.cecm.sfu.ca/projects/ISC/ISCmain.html) 207 | - [런타임 전의 전처리?](https://solved.ac/problems/tags/precomputation) 208 | - [벌리캠프?](https://solved.ac/problems/tags/berlekamp_massey) 209 | - [정규식?](https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Regular_expressions) 210 | - Python의 `in` 연산자? (한정된 경우의 KMP) 211 | - Python의 `statistics` 모듈? (선형 회귀, 평균, 분산 등) 212 | - Java의 `java.awt.geom`? (적은 수의 다각형의 불 연산) 213 | - Ruby의 `Prime`? (밀러-라빈) 214 | 215 | 해당 방법으로 문제를 훨씬 쉽게 해결할 수 있는 것을 발견했다면, 해당 문제의 출제를 재고합니다. 216 | -------------------------------------------------------------------------------- /appendix/testlib/README.md: -------------------------------------------------------------------------------- 1 | # testlib.h 비공식 문서 2 | 3 | testlib.h version `0.9.40-SNAPSHOT` 4 | 5 | ## 목차 6 | 7 | - [정의](#정의) 8 | - [Generator](#generator): 출제자 입력 생성기. 9 | - [Validator](#validator): 출제자 입력 검증기. 10 | - [Checker](#checker): 참가자 답안 검증기. 11 | - [Interactor](#interactor): 참가자 답안과 테스트의 상호작용. 12 | - 메서드 13 | - [전역 유틸리티 메서드](./utils.md) 14 | - [InStream](./instream.md): 테스트와 답안의 입력 및 검증, 및 `inf`, `ouf`, `ans`. 15 | - [opt](./opt.md): generator 옵션 파싱. 16 | - [random_t](./random_t.md): 무작위 값 생성 및 전역 변수 `rnd`. 17 | - [pattern](./pattern.md): 문자열 매칭 및 표현식. 18 | - 타입 19 | - [TResult](./tresult.md): 채점 결과. 20 | - [참고](#참고) 21 | 22 | ## 정의 23 | 24 | - $x_\mathbb{R}$: 참값 $x$를 실수로 표현한 값. 25 | - $x_\mathbb{F}$: 참값 $x$를 가장 가까운 부동소수점 값으로 표현한 값. 26 | - $\text{NaN}$: `__testlib_isNaN`이 `true`인 값. 27 | - $\pm \infty$: `__testlib_isInfinite`가 `true`인 값, i. e. $x > 10^{300}$ 혹은 $x < -10^{300}$인 값. 28 | - 기대하는 값 $x$와 실제 값 $y$의 절대 오차: $\left|x - y\right|$. 29 | - 기대하는 값 $x$와 실제 값 $y$의 상대 오차: $\left|\frac{x - y}{x}\right|$. 30 | - 공백 문자: `\t` = 9, `\n` = 10, `\r` = 13, ` ` = 32 중 하나. 31 | - 개행 문자: `\n` = 10 혹은 `\r` = 13 중 하나. 32 | - '정규 표현식': `pattern`이 처리하는 표현식. 일반적인 정규 표현식과는 조금 다릅니다. (침고: [pattern: 일반적인 정규식과 다른 점](./pattern.md#일반적인-정규식과-다른-점)) 33 | 34 | ## Generator 35 | 36 | Generator는 출제자가 입력을 생성할 때 사용하는 프로그램입니다. 37 | 38 | Generator는 `stdout`으로 테스트 케이스를 생성해 출력합니다. 이론적으로는 testlib.h를 사용할 필요는 없지만, 랜덤 데이터 생성 등에 있어서 실행 시마다 같은 결과를 보장하는 [`random_t`](random_t.md) 및 테스트 데이터 생성에 도움이 되는 여러 유틸리티를 사용하기 위해 testlib.h를 사용하는 것이 좋습니다. testlib.h를 사용하려면, `main`의 첫 줄에 `registerGen(argc, argv, 1)`을 추가해 주어야 합니다. 39 | 40 | 보통 generator는 커맨드라인 변수로 지문에서의 제한($N$, $M$ 등)을 입력받아 그 크기의 데이터를 생성합니다. 일반적인 generator 실행 방법의 예는 다음과 같습니다. 41 | 42 | ``` 43 | generator -N=100000 -M=100000 -tree 44 | ``` 45 | 46 | 이런 방법을 사용하면 generator 자체에서 데이터의 범위 등을 검증할 필요는 없으며, generator가 범위 밖의 데이터를 생성한다면 커맨드라인 변수의 값을 바꿔 주는 것으로 충분합니다. 데이터의 범위 검증 등은 validator가 담당합니다. 47 | 48 | 다만, **입력 데이터의 형식은 엄밀하게 지켜야 합니다**. 예를 들어, 언어의 한계로 인하여 토큰 단위 입력을 받는 것이 권장되지 않는 Python 사용자들은 공백으로 구분된 정수열을 다음과 같이 입력받는 것이 일반적입니다. 49 | 50 | ```python 51 | a = list(map(int, input().split(' '))) 52 | ``` 53 | 54 | 여기서, 아래와 같이 생성된 데이터를 입력받는다고 생각해 봅시다. 55 | 56 | ```cpp 57 | for (int i = 0; i < n; i++) { 58 | cout << a[i] << ' '; 59 | } 60 | cout << '\n'; 61 | ``` 62 | 63 | 이렇게 생성한 데이터의 경우 줄 끝에 공백이 있습니다. 이때 `input().split()` 시 맨 마지막 원소는 `''`가 되며, `int('')`를 실행하면 런타임 에러가 발생합니다. 이런 경우를 막기 위해 generator에서는 다음과 같이 입력을 생성해야 합니다. 64 | 65 | ```cpp 66 | for (int i = 0; i < n; i++) { 67 | if (i != 0) cout << ' '; 68 | cout << a[i]; 69 | } 70 | cout << '\n'; 71 | ``` 72 | 73 | 상기 입력은 유틸 함수 [`println`](utils.md#println)을 사용하여 간단히 작성할 수 있습니다. 74 | 75 | ```cpp 76 | println(a); 77 | ``` 78 | 79 | 참가자 입장에서 문제를 해결할 때의 일반적인 출력 방식과는 차이가 있음에 주의하십시오. 80 | 81 | 입력 형식은 이후 validator에서 한 번 더 검증하게 됩니다. 82 | 83 | - 참고: [opt](opt.md), [InStream](instream.md), [random_t](random_t.md) 84 | 85 | ## Validator 86 | 87 | > BOJ Stack에서 validator는 [데이터 검증]에 대응됩니다. 88 | 89 | Validator는 출제자의 입력이 문제의 제한과 입력 형식을 만족하는지 검증하는 프로그램입니다. Validator는 generator로 생성한 데이터를 검증해야 할 수도 있고, 여러 가지 이유로 출제자가 generator를 거치지 않고 직접 생성한 데이터를 검증해야 할 수도 있습니다. 출제자의 입력은 [`inf`](instream.md#inf-ouf-ans)에 들어오며, `main`의 첫 줄에 `registerValidation(argc, argv)`를 추가해 주어야 합니다. 90 | 91 | [InStream](instream.md)의 여러 메서드를 이용해 입력의 범위를 검증합니다. 예를 들어, [`inf.readInt(1, 100'000, "N")`](instream.md#instreamreadint)는 입력이 $1 \le N \le 100\,000$을 만족하는지 검증합니다. 이때, `inf.readInt()`는 입력이 정수를 읽어들이는 것을 의미합니다. [`inf.readLong()`](instream.md#instreamreadlong), [`inf.readDouble()`](instream.md#instreamreaddouble) 등도 있습니다. 92 | 93 | 예를 들어, [BOJ 22988](https://www.acmicpc.net/problem/22988) 〈재활용 캠페인〉은 첫 줄에 정수 $1 \le N \le 100\,000$ 과 $1 \le X \le 10^{18}$ 을 입력받고, 두 번째 줄에 $N$개의 정수 $0 \le C_i \le X$ 를 입력받는 문제입니다. 이 경우 validator는 다음과 같이 작성할 수 있습니다. 94 | 95 | ```cpp 96 | int main(int argc, char* argv[]) { 97 | registerValidation(argc, argv); 98 | 99 | // Line #1 100 | int N = inf.readInt(1, 100'000, "N"); 101 | inf.readSpace(); 102 | long long X = inf.readLong(1, (long long) 1e18l, "X"); 103 | inf.readEoln(); 104 | 105 | // Line #2 106 | inf.readLongs(N, (long long) 0, X, "C"); 107 | inf.readEoln(); 108 | 109 | inf.readEof(); 110 | } 111 | ``` 112 | 113 | - `1e18l` 대신 `1e18`로 적어도 문제는 없으나, `1e18` 정도의 크기의 값은 `double`이 정확히 표현할 수 없음에 주의합니다($10^{18}>10^{16}>2^{53}$). $10^{15}$ 이상의 값에서는 `l` 접미사를 붙여 `long double` 리터럴로 취급하는 것을 권장합니다. 114 | 115 | Validator는 문제의 제한을 만족함을 검증하기 위하여 복잡한 로직을 포함할 수도 있습니다. 예를 들어, [BOJ 28436](https://www.acmicpc.net/problem/28436) 〈돌 옮기기〉는 `W`, `B`, `.`으로만 이루어진 문자열을 입력받고, 이 문자열에 `W` 및 `B`가 적어도 하나 이상 존재함을 검증해야 합니다. 이때의 validator는 다음과 같이 작성할 수 있습니다. 116 | 117 | ```cpp 118 | int main(int argc, char *argv[]) { 119 | registerValidation(argc, argv); 120 | 121 | int T = inf.readInt(1, 10'000, "T"), totN = 0; 122 | inf.readEoln(); 123 | 124 | while (T--) { 125 | string s = inf.readToken("[WB.]{2,500000}", "s"); 126 | inf.readEoln(); 127 | 128 | ensuref( 129 | count(s.begin(), s.end(), 'W') >= 1, 130 | "there should be at least one W, but got %s instead", 131 | compress(s).c_str() 132 | ); 133 | ensuref( 134 | count(s.begin(), s.end(), 'B') >= 1, 135 | "there should be at least one B, but got %s instead", 136 | compress(s).c_str() 137 | ); 138 | totN += s.size(); 139 | ensuref( 140 | totN <= 500'000, 141 | "the sum of N over all cases should not exceed 500,000" 142 | ); 143 | } 144 | inf.readEof(); 145 | } 146 | ``` 147 | 148 | [`readEoln`](instream.md#instreamreadeoln), [`readSpace`](instream.md#instreamreadspace), [`readEof`](instream.md#instreamreadeof) 등으로 입력 형식도 엄밀히 검증하고 있음에 유의합니다. [`ensuref`](utils.md#ensuref)는 입력이 조건을 만족하지 않을 경우, `format`으로 포매팅된 메시지를 출력하고 프로그램을 종료합니다. `ensuref`는 `assert`와 유사하게 동작합니다. 149 | 150 | - 참고: [InStream](instream.md), [pattern](pattern.md), [ensuref](utils.md#ensuref) 151 | 152 | ## Checker 153 | 154 | > BOJ Stack에서 checker는 [스페셜 저지]에 대응됩니다. 155 | 156 | Checker는 참가자의 답안이 정답인지 검증하는 프로그램입니다. Checker는 `inf`, `ans`와 `ouf`를 이용해 출제자가 준비한 테스트 케이스와 출제자의 답안, 그리고 참가자의 답안을 읽어들입니다. `main`의 첫 줄에 `registerTestlibCmd(argc, argv)`를 추가해 주어야 합니다. 157 | 158 | 참가자의 입력은 validator에서 출제자의 입력을 검증하던 것보다는 덜 엄격하게 검증해도 괜찮습니다. 오히려 덜 업격하게 검증하는 것이 권장됩니다. 예를 들어, 5개의 정수 1, 2, 3, 4, 5를 공백으로 구분하여 출력할 때 참가자가 `1 2 3 4 5 `와 같이 출력했다면, 맨 뒤의 띄어쓰기가 있더라도 정답으로 처리합니다. 159 | 160 | 일반적으로 checker에서는 [`readEoln`](instream.md#instreamreadeoln), [`readSpace`](instream.md#instreamreadspace), [`readEof`](instream.md#instreamreadeof) 등을 사용하지 않고, 토큰 단위로만 읽습니다. 161 | 162 | 채점이 완료된 후 토큰이 남아 있을 경우 [`_pe`](tresult.md#_pe)로 자동 종료되므로, 출력 형식에 정의한 대로 참가자의 출력의 모든 토큰을 읽어야 하며, 일부 토큰만 읽고 도중 종료하면 안 됩니다. 같은 이유로, 참가자의 입력에 토큰이 남아 있는지를 검증할 필요는 없습니다. (참고: [`_dirt`](tresult.md#)) 163 | 164 | 예를 들어, [BOJ 1008](https://www.acmicpc.net/problem/1008) 〈A/B〉의 checker는 [`doubleCompare`](utils.md#doublecompare)를 사용하여 아래와 같이 작성할 수 있습니다. 165 | 166 | ```cpp 167 | int main(int argc, char *argv[]) { 168 | registerTestlibCmd(argc, argv); 169 | 170 | // Participant answer 171 | double pans = ouf.readDouble(); 172 | 173 | // Jury answer 174 | double jans = ans.readDouble(); 175 | 176 | if (doubleCompare(jans, pans, 1e-9)) { 177 | quitf(_ok, "OK %lf", pans); 178 | } else { 179 | quitf(_wa, "Expected %lf, but found %lf", jans, pans); 180 | } 181 | } 182 | ``` 183 | 184 | - 참고: [InStream](instream.md), [Strict mode](instream.md#strict-mode), [TResult](tresult.md) 185 | - 참고: [doubleCompare](utils.md#doublecompare) 186 | 187 | ## Interactor 188 | 189 | > BOJ Stack에 interactor를 올리기 위해서는 스타트링크에 별도로 문의해야 합니다. 190 | 191 | Interactor는 인터랙티브 문제에서 참가자의 프로그램과 상호작용을 하는 프로그램입니다. Interactor는 우선 `inf`를 통해 출제자의 테스트 케이스를 읽어들인 후, `ouf`를 통해 참가자의 프로그램의 출력을 읽고 `std::cout`을 통해 다시 입력을 전달하는 상호작용을 반복합니다. `main`의 첫 줄에 `registerInteraction(argc, argv)`를 추가해 주어야 합니다. 192 | 193 | `ouf`를 읽을 때에는 checker와 동일하게 토큰 단위로 읽는 것이 권장됩니다. `cout`으로 한 줄을 출력한 후에는 반드시 `endl`이나 `cout.flush()` 등을 이용하여 출력 스트림을 flush하여야 합니다. 194 | 195 | ### Checker를 같이 사용하는 경우 196 | 197 | Interactor는 추가적인 검증이 필요한 정보를 `tout`으로 출력할 수 있습니다. `tout`으로 출력한 파일은 checker에서 `ouf`로 읽게 됩니다. 출제자의 답안에 의해 작성된 `tout`은 interactor와 checker에서 `ans`를 통해 읽을 수 있습니다. 참가자의 코드는 interactor와 checker에서 모두 `_ac`를 받아야 통과합니다. 198 | 199 | `tout`은 `cout`과 같은 방식으로 동작하며, `tout << n << endl;`과 같이 쓸 수 있습니다. 200 | 201 | ### Checker를 사용하지 않는 경우 202 | 203 | 인터랙티브 문제를 만들 때, 별도의 checker 없이 모든 채점을 interactor 내에서 하게 되는 경우가 많습니다. 이런 경우에도 Polygon에서는 checker가 없으면 채점이 진행되지 않기 때문에, 다음과 같은 dummy checker를 사용할 수 있습니다. 204 | 205 | ```cpp 206 | #include "testlib.h" 207 | 208 | int main(int argc, char** argv) { 209 | registerTestlibCmd(argc, argv); 210 | while (!ouf.seekEof()) { 211 | ouf.readToken("[!-~]+", "dummy"); 212 | } 213 | quitf(_ok, "OK"); 214 | return 0; 215 | } 216 | ``` 217 | 218 | ### 문제 예시 219 | 220 | > 1 이상 15 이하의 정수를 알아맞혀 보자. 221 | > 222 | > 다음을 한 줄에 출력하여 인터랙터에게 쿼리를 할 수 있다. 쿼리는 최대 4번까지 할 수 있다. 223 | > 224 | > * `n`: 숨겨진 값이 $n$인지 질문한다. ($1 \le n \le 15$) 225 | > 226 | > 쿼리의 결과는 한 줄을 입력받아 알 수 있다. 가능한 결과는 다음과 같다. 227 | > 228 | > * `-1`: 숨겨진 값은 $n$보다 작다. 229 | > * `0`: 숨겨진 값은 $n$과 같다. 230 | > * `1`: 숨겨진 값은 $n$보다 크다. 231 | > 232 | > `0`의 결과를 받았다면 성공적으로 숨겨진 값을 찾은 것이다. 이 경우에는 더 이상 쿼리를 출력하지 않고 즉시 프로그램을 종료해야 한다. 233 | 234 | 이 문제의 interactor는 다음과 같이 작성할 수 있습니다. 테스트 케이스 파일에는 숨겨진 정수가 들어 있습니다. 235 | 236 | ```cpp 237 | #include "testlib.h" 238 | 239 | int main(int argc, char** argv) { 240 | registerInteraction(argc, argv); 241 | int hidden = inf.readInt(); 242 | bool found = false; 243 | for (int tries = 0; tries < 4; tries++) { 244 | int guess = ouf.readInt(1, 15); 245 | if (hidden > guess) { 246 | cout << 1 << endl; 247 | } else if (hidden == guess) { 248 | cout << 0 << endl; 249 | found = true; 250 | break; 251 | } else { 252 | cout << -1 << endl; 253 | } 254 | } 255 | if (!found) { 256 | quitf(_wa, "failed to find the hidden number"); 257 | } 258 | quitf(_ok, "found the hidden number"); 259 | return 0; 260 | } 261 | ``` 262 | 263 | ## 참고 264 | 265 | - [GitHub: MikeMirzayanov/testlib](https://github.com/MikeMirzayanov/testlib) 266 | - [Polygon 플랫폼](https://polygon.codeforces.com/) 267 | - [Codeforces: Briefly about testlib.h](https://codeforces.com/testlib) 268 | - [Codeforces: Generators with testlib.h](https://codeforces.com/blog/entry/18291) 269 | - [Codeforces: Validators with testlib.h](https://codeforces.com/blog/entry/18426) 270 | - [Codeforces: Interactors with testlib.h](https://codeforces.com/blog/entry/18455) 271 | - [Codeforces: Checkers with testlib.h](https://codeforces.com/blog/entry/18431) 272 | -------------------------------------------------------------------------------- /appendix/testlib/utils.md: -------------------------------------------------------------------------------- 1 | # 전역 유틸리티 메서드 2 | 3 | 아래 메서드들은 전역으로 정의되며, checker, validator, interactor, generator 모두에서 사용할 수 있습니다. 4 | 5 | ## 목차 6 | 7 | - [목차](#목차) 8 | - [검증](#검증) 9 | - [ensure](#ensure) 10 | - [ensuref](#ensuref) 11 | - [채점](#채점) 12 | - [quit](#quit) 13 | - [quitp](#quitp) 14 | - [quitf](#quitf) 15 | - [quitif](#quitif) 16 | - [실수형](#실수형) 17 | - [doubleCompare](#doublecompare) 18 | - [doubleDelta](#doubledelta) 19 | - [문자열](#문자열) 20 | - [compress](#compress) 21 | - [format](#format) 22 | - [isBlanks](#isblanks) 23 | - [isEof](#iseof) 24 | - [isEoln](#iseoln) 25 | - [join](#join) 26 | - [lowerCase](#lowercase) 27 | - [split](#split) 28 | - [toHumanReadableString](#tohumanreadablestring) 29 | - [tokenize](#tokenize) 30 | - [toString](#tostring) 31 | - [trim](#trim) 32 | - [vtos](#vtos) 33 | - [upperCase](#uppercase) 34 | - [수와 문자열](#수와-문자열) 35 | - [englishEnding](#englishending) 36 | - [equals](#equals) 37 | - [removeDoubleTrailingZeroes](#removedoubletrailingzeroes) 38 | - [출력](#출력) 39 | - [println](#println) 40 | - [채점 옵션 처리](#채점-옵션-처리) 41 | 42 | ## 검증 43 | 44 | ### ensure 45 | 46 | - `#define ensure(cond)` 47 | - `cond`: 참이어야 하는 조건. 48 | 49 | `cond`가 `true`일 것을 보장합니다. 50 | 51 | 자세한 이유를 명시하기 위하여 [`ensuref`](#ensuref)를 사용하는 것이 좋습니다. 52 | 53 | ### ensuref 54 | 55 | - `inline void ensuref(bool cond, const char *format, ...)` 56 | - `cond`: 참이어야 하는 조건. 57 | - `format`, `...`: `printf` 스타일의 포맷 문자열 및 가변 인자. 58 | 59 | `cond`가 `true`일 것을 보장합니다. 60 | 61 | `cond`가 `false`인 경우, `format`을 포맷 문자열로 사용하여 `printf` 스타일의 메시지를 출력하고 [`_fail`](tresult.md#_fail) 결과로 종료합니다. 62 | 63 | ## 채점 64 | 65 | ### quit 66 | 67 | - `void quit(TResult result, const std::string &msg)` 68 | - `void quit(TResult result, const char *msg)` 69 | - `result`: 채점 결과. 70 | - `msg`: 메시지. 71 | 72 | 채점을 `result` 결과로 종료합니다. (참고: [TResult](tresult.md)) 73 | 74 | 포맷 문자열을 사용하고자 하는 경우, [`quitf`](#quitf)를 사용하는 것이 좋습니다. 75 | 76 | ### quitp 77 | 78 | - `void quitp(F points, const char *format, ...)` 79 | - `F`: 점수의 자료형. 80 | - `points`: 채점 결과 참가자가 획득한 점수. 81 | - `format`, `...`: `printf` 스타일의 포맷 문자열 및 가변 인자. 82 | 83 | 채점을 `points`의 점수를 획득한 것으로 하여 종료합니다. 84 | 85 | ### quitf 86 | 87 | - `void quitf(TResult result, const char *msg, ...)` 88 | - `result`: 채점 결과. 89 | - `msg`, `...`: `printf` 스타일의 포맷 문자열 및 가변 인자. 90 | 91 | 채점을 `result` 결과로 종료합니다. (참고: [TResult](tresult.md)) 92 | 93 | ### quitif 94 | 95 | - `void quitif(bool condition, TResult result, const char *format, ...)` 96 | - `condition`: 채점을 종료할지 여부. 97 | - `result`: 채점 결과. 98 | - `format`, `...`: `printf` 스타일의 포맷 문자열 및 가변 인자. 99 | 100 | `condition`이 `true`인 경우, 채점을 `result` 결과로 종료합니다. (참고: [TResult](tresult.md)) 101 | 102 | ## 실수형 103 | 104 | ### doubleCompare 105 | 106 | - `inline bool doubleCompare(double expected, double result, double MAX_DOUBLE_ERROR)` 107 | - `expected`: 기대하는 값. 108 | - `result`: 실제 값. 109 | - `MAX_DOUBLE_ERROR`: 오차의 최댓값. 110 | 111 | `expected`와 `result`의 오차가 일정 값 이하인지 확인합니다. 112 | 113 | `expected`와 `result`의 절대/상대 오차가 $\left(\texttt{MAX\\\_DOUBLE\\\_ERROR} + 10^{-15}_\mathbb{F}\right)\_\mathbb{F}$ 이하인지 확인합니다. 114 | 115 | `expected` 혹은 `result`가 $\text{NaN}$인 경우, 둘 모두 $\text{NaN}$인 경우에만 `true`를 반환합니다. `expected` 혹은 `result`가 $\pm \infty$인 경우, 둘 모두 $\pm \infty$이며 부호가 같은 경우에만 `true`를 반환합니다. 116 | 117 | ### doubleDelta 118 | 119 | - `inline double doubleDelta(double expected, double result)` 120 | - `expected`: 기대하는 값. 121 | - `result`: 실제 값. 122 | 123 | `expected`와 `result`의 오차를 계산합니다. 124 | 125 | $\texttt{expected} > 10^{-9}_\mathbb{F}$라면, `expected`와 `result`의 절대/상대 오차 중 작은 것을 반환합니다. 그렇지 않다면, `expected`와 `result`의 절대 오차를 반환합니다. 126 | 127 | ## 문자열 128 | 129 | ### compress 130 | 131 | - `inline std::string compress(const std::string &s)` 132 | - `s`: 문자열. 133 | 134 | 문자열 `s`에 `\0` = 0이 있다면 전부 `~` = 126으로 변경하고, 64글자 이하가 되도록 합니다. 135 | 136 | `s`가 64글자가 넘는다면, `s`의 앞 30글자와 뒤 30글자를 제외한 부분을 `...`으로 대체합니다. 137 | 138 | ### format 139 | 140 | - `std::string format(const char *fmt, ...)` 141 | - `std::string format(const std::string fmt, ...)` 142 | - `fmt`: 형식 문자열. `printf`와 동일한 형식을 사용합니다. 143 | 144 | `printf`와 동일한 형식을 사용하는 형식 문자열 `fmt`와 가변 인자를 받아, 형식 문자열에 가변 인자를 적용한 결과를 반환합니다. 145 | 146 | - `format("a_%d", 1)` → `"a_1"` 147 | - `format("a_(%d,%d)", 1, 2)` → `"a_(1,2)"` 148 | 149 | ### isBlanks 150 | 151 | - `template inline bool isBlanks(C c)` 152 | - `C`: 문자의 타입. 153 | - `c`: 문자. 154 | 155 | `c`가 공백 문자인지 확인합니다. 156 | 157 | `C`는 문자 혹은 정수형이어야 합니다. 158 | 159 | ### isEof 160 | 161 | - `template inline bool isEof(C c)` 162 | - `C`: 문자의 타입. 163 | - `c`: 문자. 164 | 165 | `c`가 EOF(255)인지 확인합니다. 166 | 167 | `C`는 문자 혹은 정수형이어야 합니다. 168 | 169 | ### isEoln 170 | 171 | - `template inline bool isEoln(C c)` 172 | - `C`: 문자의 타입. 173 | - `c`: 문자. 174 | 175 | `c`가 개행 문자인지 확인합니다. 176 | 177 | `C`는 문자 혹은 정수형이어야 합니다. 178 | 179 | ### join 180 | 181 | - `template std::string join(const _Collection &collection)` 182 | - `template std::string join(const _Collection &collection, _Separator separator)` 183 | - `template std::string join(_ForwardIterator first, _ForwardIterator last)` 184 | - `template std::string join(_ForwardIterator first, _ForwardIterator last, _Separator separator)` 185 | - `_Collection`, `_ForwardIterator`: 컬렉션 또는 반복자 타입. 186 | - `_Separator`: 구분자의 타입. 187 | - `collection`: 컬렉션. 188 | - `first`: 컬렉션의 시작 반복자. 189 | - `last`: 컬렉션의 끝 반복자. 190 | - `separator`: 구분자(명시하지 않으면, ` ` = 20). 191 | 192 | 컬렉션 `collection`의 모든 원소, 또는 반복자 `first`..`last`로 정의된 구간을 구분자 `separator`로 구분하여 문자열로 표현한 값을 반환합니다. 193 | 194 | `_Collection`은 `_Collection::begin()`, `_Collection::end()`가 정의되어 있어야 하며, forward 반복자를 반환해야 합니다. `first`와 `last`는 forward 반복자여야 합니다. `_Collection` 및 `_ForwardIterator`의 원소 `T`는 `operator<<(std::stringstream, T)`가 정의되어 있어야 합니다. 195 | 196 | `_Seperator`는 `operator<<(std::stringstream, _Separator)`가 정의되어 있어야 합니다. 197 | 198 | ### lowerCase 199 | 200 | - `inline std::string lowerCase(std::string s)` 201 | - `s`: 문자열. 202 | 203 | 문자열 `s`의 모든 문자를 소문자로 바꾼 문자열을 반환합니다. 204 | 205 | ### split 206 | 207 | - `std::vector split(const std::string &s, char separator)` 208 | - `std::vector split(const std::string &s, const std::string &separators)` 209 | - `s`: 문자열. 210 | - `separator`: 구분자. 211 | - `separators`: 구분자들. 212 | 213 | 문자열 `s`를 구분자 `separator` 혹은 여러 구분자들 `separators` 중 하나로 구분하여 문자열의 벡터로 표현한 값을 반환합니다. 구분자가 $k$번 나타난다면, 반환되는 벡터의 크기는 $k+1$입니다. 즉, 빈 문자열이 포함될 수 있습니다. 214 | 215 | ### toHumanReadableString 216 | 217 | - `template static std::string toHumanReadableString(const T &n)` 218 | - `template static std::string toHumanReadableString(const T &n, std::false_type)` 219 | - `template static std::string toHumanReadableString(const T &n, std::true_type)` 220 | - `T`: 포맷할 값의 타입. 221 | - `n`: 포맷할 값. 222 | 223 | 정수 `n`을 문자열로 표현했을 때 맨 뒤의 0을 축약하여 사람이 읽기 쉬운 형태로 표현한 값을 반환합니다. 224 | 225 | 맨 뒤의 0의 개수가 7개 이상인 경우에 지수 형태로 표현합니다. 226 | 227 | `T`는 정수형이어야 합니다. 228 | 229 | - `toHumanReadableString(10000)` → `"10000"` 230 | - `toHumanReadableString(10_000_000)` → `"10^7"` 231 | - `toHumanReadableString(31_400_000_000LL)` → `"314*10^8"` 232 | 233 | ### tokenize 234 | 235 | - `std::vector tokenize(const std::string &s, char separator)` 236 | - `std::vector tokenize(const std::string &s, const std::string &separators)` 237 | 238 | 문자열 `s`를 구분자 `separator` 혹은 여러 구분자들 `separators` 중 하나로 구분하고, 이 중 빈 문자열을 제외하여 문자열의 벡터로 표현한 값을 반환합니다. 239 | 240 | ### toString 241 | 242 | - `template static std::string toString(const T &t)` 243 | 244 | = [vtos](#vtos). 245 | 246 | ### trim 247 | 248 | - `inline std::string trim(const std::string &s)` 249 | - `s`: 문자열. 250 | 251 | 문자열 `s`의 앞/뒤에 있는 공백 문자를 제거한 문자열을 반환합니다. 252 | 253 | ### vtos 254 | 255 | - `template static std::string vtos(const T &t)` 256 | - `template static std::string vtos(const T &t, std::true_type)` 257 | - `template static std::string vtos(const T &t, std::false_type)` 258 | - `T`: 포맷할 값의 타입. 259 | - `t`: 포맷할 값. 260 | 261 | `t`를 문자열로 표현한 값을 반환합니다. 262 | 263 | `T`는 정수형이거나, `operator<<(std::stringstream, T)`가 정의되어 있는 타입이어야 합니다. 264 | 265 | ### upperCase 266 | 267 | - `inline std::string upperCase(std::string s)` 268 | - `s`: 문자열. 269 | 270 | 문자열 `s`의 모든 문자를 대문자로 바꾼 문자열을 반환합니다. 271 | 272 | ## 수와 문자열 273 | 274 | ### englishEnding 275 | 276 | - `inline std::string englishEnding(int x)` 277 | - `x`: 정수. 278 | 279 | `x`의 영어 서수 표현에서의 접미사를 반환합니다. 음수에 대해서는 제대로 된 동작을 보장하지 않습니다. 280 | 281 | - `englishEnding(1)` → `"st"` 282 | - `englishEnding(12)` → `"th"` 283 | - `englishEnding(23)` → `"rd"` 284 | 285 | ### equals 286 | 287 | - `static inline bool equals(long long integer, const char *s)` 288 | - `static inline bool equals(unsigned long long integer, const char *s)` 289 | - `integer`: 정수. 290 | - `s`: 문자열. 291 | 292 | `integer`를 문자열로 표현한 값이 `s`와 일치하는지 확인합니다. 293 | 294 | `s` 앞의 0은 무시하지 않으며, `integer`가 음수인 경우에는 부호를 포함하여 일치하는지 확인합니다. 295 | 296 | - `equals(123, "123")` → `true` 297 | - `equals(123, "0123")` → `false` 298 | - `equals(-123, "-123")` → `true` 299 | 300 | ### removeDoubleTrailingZeroes 301 | 302 | - `static std::string removeDoubleTrailingZeroes(std::string value)` 303 | - `value`: 실수를 표현하는 문자열. 304 | 305 | 실수를 표현하는 문자열 `value`의 끝에 있는 0을 제거한 값을 반환합니다. 306 | 307 | 원래 문자열에 소수점이 없었다면 새로 추가하지 않습니다. 원래 문자열의 마지막 문자가 소수점이었다면, 맨 뒤에 `0`을 추가합니다. 308 | 309 | - `removeDoubleTrailingZeroes("1.000000")` → `"1.0"` 310 | - `removeDoubleTrailingZeroes("1.")` → `"1.0"` 311 | 312 | ## 출력 313 | 314 | ### println 315 | 316 | - `template void println(const T &x)` 317 | - `template void println(const A *a, const A *b)` 318 | - `template typename __testlib_enable_if::value, void>::type println(const A &a, const B &b)` 319 | - `template typename __testlib_enable_if::value, void>::type println(const A &a, const B &b)` 320 | - `template<> void println(const char *a, const char *b)` 321 | - `template void println(const A &a, const B &b, const C &c)` 322 | - `template void println(const A &a, const B &b, const C &c, const D &d)` 323 | - `template void println(const A &a, const B &b, const C &c, const D &d, const E &e)` 324 | - `template void println(const A &a, const B &b, const C &c, const D &d, const E &e, const F &f)` 325 | - `template void println(const A &a, const B &b, const C &c, const D &d, const E &e, const F &f, const G &g)` 326 | - `A`, `B`, `C`, `D`, `E`, `F`, `G`: 출력할 값의 타입. 327 | - `a`, `b`, `c`, `d`, `e`, `f`, `g`: 출력할 값. 328 | 329 | 여러 값을 한 줄으로 하여 표준 출력 스트림으로 출력합니다. 인자는 7개까지 받을 수 있습니다. 줄 끝에 개행 문자를 출력하며, 출력 버퍼를 비웁니다(flush). 330 | 331 | 특별하게, 인자가 2개인 경우이면서 두 인자의 타입이 문자열 포인터가 아닌 포인터라면, 첫 번째 인자를 `begin`, 두 번째 인자를 `end`로 간주하여 `begin`..`end`의 구간에 있는 원소들을 출력합니다. 문자열 포인터의 경우에는 문자열 두 개를 출력합니다. 332 | 333 | 또한, 인자가 2개인 경우이면서 두 인자가 모두 반복자라면, 마찬가지로 첫 번째 인자를 `begin`, 두 번째 인자를 `end`로 간주하여 `begin`..`end`의 구간에 있는 원소들을 출력합니다. 334 | 335 | `A`, `B`, `C`, `D`, `E`, `F`, `G`는 `operator<<(std::stringstream, T)`가 정의되어 있어야 합니다. 또한, 인자가 2개인 경우 중 앞서 언급한 특별한 경우에 대해서, 반복 또는 포인터가 가리키는 값 `T`에 대해서도 `operator<<(std::stringstream, T)`가 정의되어 있어야 합니다. 336 | 337 | ## 채점 옵션 처리 338 | 339 | → [opt](./opt.md) 340 | -------------------------------------------------------------------------------- /appendix/testlib/instream.md: -------------------------------------------------------------------------------- 1 | # InStream 2 | 3 | - 해당 내용: **Validator**, **Checker**, **Interactor** 4 | 5 | `InStream`은 입력과 출력에 대한 검증 등을 쉽게 할 수 있는 여러 유틸리티 함수를 제공합니다. 6 | 7 | ## 목차 8 | 9 | - [목차](#목차) 10 | - [inf, ouf, ans](#inf-ouf-ans) 11 | - [주요 입력 함수](#주요-입력-함수) 12 | - [Strict mode](#strict-mode) 13 | - [일반](#일반) 14 | - [InStream::skipBlanks](#instreamskipblanks) 15 | - [InStream::curChar](#instreamcurchar) 16 | - [InStream::skipChar](#instreamskipchar) 17 | - [InStream::readChar](#instreamreadchar) 18 | - [InStream::nextChar](#instreamnextchar) 19 | - [InStream::readSpace](#instreamreadspace) 20 | - [InStream::unreadChar](#instreamunreadchar) 21 | - [InStream::eof](#instreameof) 22 | - [InStream::seekEof](#instreamseekeof) 23 | - [InStream::eoln](#instreameoln) 24 | - [InStream::seekEoln](#instreamseekeoln) 25 | - [InStream::nextLine](#instreamnextline) 26 | - [InStream::readEoln](#instreamreadeoln) 27 | - [InStream::readEof](#instreamreadeof) 28 | - [토큰](#토큰) 29 | - [InStream::readToken](#instreamreadtoken) 30 | - [InStream::readTokens](#instreamreadtokens) 31 | - [InStream::readTokenTo](#instreamreadtokento) 32 | - [InStream::readWord](#instreamreadword) 33 | - [InStream::readWords](#instreamreadwords) 34 | - [InStream::readWordTo](#instreamreadwordto) 35 | - [InStream::readLine](#instreamreadline) 36 | - [InStream::readLines](#instreamreadlines) 37 | - [InStream::readLineTo](#instreamreadlineto) 38 | - [InStream::readString](#instreamreadstring) 39 | - [InStream::readStrings](#instreamreadstrings) 40 | - [InStream::readStringTo](#instreamreadstringto) 41 | - [정수](#정수) 42 | - [InStream::readInt](#instreamreadint) 43 | - [InStream::readInts](#instreamreadints) 44 | - [InStream::readInteger](#instreamreadinteger) 45 | - [InStream::readIntegers](#instreamreadintegers) 46 | - [InStream::readLong](#instreamreadlong) 47 | - [InStream::readLongs](#instreamreadlongs) 48 | - [InStream::readUnsignedLong](#instreamreadunsignedlong) 49 | - [InStream::readUnsignedLongs](#instreamreadunsignedlongs) 50 | - [실수](#실수) 51 | - [InStream::readDouble](#instreamreaddouble) 52 | - [InStream::readDoubles](#instreamreaddoubles) 53 | - [InStream::readReal](#instreamreadreal) 54 | - [InStream::readReals](#instreamreadreals) 55 | - [InStream::readStrictDouble](#instreamreadstrictdouble) 56 | - [InStream::readStrictDoubles](#instreamreadstrictdoubles) 57 | - [InStream::readStrictReal](#instreamreadstrictreal) 58 | - [InStream::readStrictReals](#instreamreadstrictreals) 59 | 60 | ## inf, ouf, ans 61 | 62 | - `InStream inf`: Validator, checker, interactor에서 테스트 케이스 파일. 63 | - `InStream ouf`: Checker, interactor에서 참가자의 출력. 64 | - `InStream ans`: Checker, interactor에서 출제자의 답안. 65 | 66 | `inf`, `ouf`, `ans`는 `InStream`의 인스턴스로, 전역 변수입니다. 67 | 68 | ## 주요 입력 함수 69 | 70 | | 형식 | 타입 | 한 개 입력 | 여러 개 입력 | 71 | | --------------------------- | -------------------- | -------------------------------------------------------------------- | ----------------------------------------------- | 72 | | 토큰 (공백으로 구분됨) | `std::string` | [readToken](#instreamreadtoken), [readTokenTo](#instreamreadtokento) | [readTokens](#instreamreadtokens) | 73 | | 줄 (공백을 무시하지 않음) | `std::string` | [readLine](#instreamreadline) | [readLines](#instreamreadlines) | 74 | | 32비트 정수 | `int` | [readInt](#instreamreadint) | [readInts](#instreamreadints) | 75 | | 64비트 정수 | `long long` | [readLong](#instreamreadlong) | [readLongs](#instreamreadlongs) | 76 | | 부호 없는 64비트 정수 | `unsigned long long` | [readUnsignedLong](#instreamreadunsignedlong) | [readUnsignedLongs](#instreamreadunsignedlongs) | 77 | | 실수 (과학적 표기법 허용) | `double` | [readDouble](#instreamreaddouble) | [readDoubles](#instreamreaddoubles) | 78 | | 실수 (과학적 표기법 비허용) | `double` | [readStrictDouble](#instreamreadstrictdouble) | [readStrictDoubles](#instreamreadstrictdoubles) | 79 | 80 | ## Strict mode 81 | 82 | Strict mode는 입력 형식을 조금 더 엄밀하게 검사하는 모드입니다. 공백 문자와 개행 문자가 나타나는 경우, 정확히 읽어야 합니다. 83 | 84 | Strict mode는 **validator의 `inf`에만 적용**되며, validator가 아닌 경우(예를 들어 checker)의 `inf`에는 적용되지 않고, `ouf`과 `ans`에는 어떤 모드일 때에도 적용되지 않습니다. 85 | 86 | 다음 코드를 예로 들겠습니다. 위는 입력 데이터, 아래는 testlib.h를 사용하는 코드입니다. 87 | 88 | ``` 89 | 3 1 4 1 5 90 | ``` 91 | 92 | ```cpp 93 | for (int i = 0; i < 5; i++) 94 | inf.readInt(); 95 | ``` 96 | 97 | Strict mode가 꺼져 있다면, testlib.h는 5개의 정수를 성공적으로 읽습니다. Strict mode가 켜져 있다면, 다음과 같은 오류가 발생하며 종료됩니다. 98 | 99 | ```cpp 100 | quit(_pe, "Unexpected white-space - token expected"); 101 | ``` 102 | 103 | Strict mode에서 위 데이터를 올바르게 읽는 코드는 다음과 같습니다. 104 | 105 | ```cpp 106 | for (int i = 0; i < 5; i++) { 107 | if (i != 0) inf.readSpace(); 108 | inf.readInt(); 109 | } 110 | inf.readEoln(); 111 | inf.readEof(); 112 | ``` 113 | 114 | Validator의 경우 출제진이 생성한 입력은 위와 같이 검증해야 합니다. Checker에서 참가자의 입력을 검증할 때에는 위와 같이 하지 않아도 괜찮으며, 위와 같이 하지 않는 것이 오히려 권장됩니다. (TODO: Validator와 Checker에 대한 링크 걸기) 115 | 116 | ## 일반 117 | 118 | ### InStream::skipBlanks 119 | 120 | - `void skipBlanks()` 121 | 122 | 현재 위치 이후의 연속된 공백 문자들을 모두 무시하고, 공백 문자가 아닌 첫 위치로 커서를 이동합니다. 123 | 124 | ### InStream::curChar 125 | 126 | - `char curChar()` 127 | 128 | 현재 위치의 문자를 반환합니다. 커서는 이동하지 않습니다. 129 | 130 | ### InStream::skipChar 131 | 132 | - `void skipChar()` 133 | 134 | 커서를 한 단계 뒤로 이동합니다. 공백을 무시하지 않습니다. 135 | 136 | ### InStream::readChar 137 | 138 | - `char readChar()` 139 | - `char readChar(char c)` 140 | - `c`: 읽을 문자. 141 | 142 | 현재 위치의 문자를 읽습니다. 커서는 한 단계 뒤로 이동합니다. 공백을 무시하지 않으며, 현재 위치에 공백이 있을 경우 공백을 그대로 읽습니다. 143 | 144 | `c`가 주어진 경우, 읽은 문자가 `c`가 아닐 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 145 | 146 | ### InStream::nextChar 147 | 148 | - `char nextChar()` 149 | 150 | = [readChar()](#instreamnextchar). 151 | 152 | ### InStream::readSpace 153 | 154 | - `void readSpace()` 155 | 156 | = [readChar(`' '`)](#instreamreadchar) 157 | 158 | ### InStream::unreadChar 159 | 160 | - `void unreadChar(char c)` 161 | - `c`: 되돌릴 문자. 162 | 163 | 커서를 한 단계 앞으로 이동하면서, `c`를 현재 위치에 삽입합니다. 공백을 무시하지 않습니다. 164 | 165 | ### InStream::eof 166 | 167 | - `bool eof()` 168 | 169 | 현재 위치가 EOF인지 확인합니다. 커서는 이동하지 않습니다. 170 | 171 | ### InStream::seekEof 172 | 173 | - `book seekEof()` 174 | 175 | 공백 문자가 아닌 첫 위치로 커서를 이동하고, 현재 위치가 EOF인지 확인합니다. 176 | 177 | ### InStream::eoln 178 | 179 | - `bool eoln()` 180 | 181 | 현재 위치에 개행 시퀀스가 있는지 확인합니다. 현재 위치에 개행 시퀀스가 있다면, 개행 문자 이후의 첫 문자로 커서를 이동하고, 그렇지 않다면 커서는 이동하지 않습니다. 공백을 무시하지 않습니다. 개행 시퀀스는 `\r\n` = 13 10 혹은 `\n` = 10 중 하나입니다. 182 | 183 | 단, Strict mode에서는 Windows 환경일 경우에는 `\r\n`만을 개행 시퀀스로 보며, 그렇지 않은 환경일 경우에는 `\n`만을 개행 시퀀스로 봅니다. 184 | 185 | ### InStream::seekEoln 186 | 187 | - `bool seekEoln()` 188 | 189 | 공백 문자가 아닌 첫 위치로 커서를 이동하고, 현재 위치에 개행 시퀀스가 있는지 확인합니다. 190 | 191 | ### InStream::nextLine 192 | 193 | - `void nextLine()` 194 | 195 | 다음 행의 첫 문자 위치로 커서를 이동합니다. 196 | 197 | ### InStream::readEoln 198 | 199 | - `void readEoln()` 200 | 201 | 현재 위치에 개행 시퀀스가 있는지 확인합니다. 개행 시퀀스가 없다면 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 개행 시퀀스가 있다면, 개행 문자 이후의 첫 문자로 커서를 이동합니다. 공백을 무시하지 않습니다. 개행 시퀀스는 `\r\n` = 13 10 혹은 `\n` = 10 중 하나입니다. 202 | 203 | Strict mode에서는 Windows 환경일 경우에는 `\r\n`만을 개행 시퀀스로 보며, 그렇지 않은 환경일 경우에는 `\n`만을 개행 시퀀스로 봅니다. 204 | 205 | ### InStream::readEof 206 | 207 | - `void readEof()` 208 | 209 | 현재 위치가 EOF인지 확인합니다. 현재 위치가 EOF가 아니라면 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 210 | 211 | ## 토큰 212 | 213 | ### InStream::readToken 214 | 215 | - `std::string readToken()` 216 | - `std::string readToken(const std::string &ptrn, const std::string &variableName = "")` 217 | - `std::string readToken(const pattern &p, const std::string &variableName = "")` 218 | - `ptrn`, `p`: 입력 검증에 사용할 정규 표현식. 219 | - `variableName`: 변수 이름. 220 | 221 | 공백 문자로 구분된 토큰을 읽습니다. 공백은 무시합니다. 커서는 토큰의 마지막 문자 이후로 이동합니다. 222 | 223 | `ptrn` 혹은 `p`를 명시하는 경우, 명시된 [정규 표현식](./pattern.md)을 만족하는 토큰을 읽습니다. 정규 표현식에 공백 문자 리터럴(`\ ` 등)이 있을 경우 의도한 대로 동작하지 않을 수 있습니다. 만약 읽은 토큰이 정규 표현식을 만족하지 않는다면 `_wa` 결과로 종료합니다. 224 | 225 | Strict mode에서는 공백을 무시하지 않으며, 현재 위치가 공백임에도 불구하고 `readToken`을 수항하는 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 226 | 227 | Validator에서 `inf`의 입력을 검증하는 경우, `ptrn`, `p`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 228 | 229 | ### InStream::readTokens 230 | 231 | - `std::vector readTokens(int size, int indexBase = 1)` 232 | - `std::vector readTokens(int size, const std::string &ptrn, const std::string &variablesName = "", int indexBase = 1)` 233 | - `std::vector readTokens(int size, const pattern &p, const std::string &variablesName = "", int indexBase = 1)` 234 | - `size`: 읽을 토큰의 개수. 235 | - `ptrn`, `p`: 입력 검증에 사용할 정규 표현식. 236 | - `variablesName`: 변수 이름. 237 | - `indexBase`: 입력 오류 시 출력할 인덱스의 시작 값. 238 | 239 | 공백으로 구분된 토큰 `size`개를 읽습니다. 토큰과 토큰 사이에 공백이 여러 개 있어도 되며, 이 경우 연속된 여러 개의 공백을 하나의 구분자로 봅니다. 즉, 반환된 벡터에는 빈 문자열이 들어 있지 않습니다. 커서는 `size`번째 토큰의 마지막 문자 이후로 이동합니다. 240 | 241 | `ptrn` 혹은 `p`를 명시하는 경우, 명시된 [정규 표현식](./pattern.md)을 만족하는 토큰을 읽습니다. 정규 표현식에 공백 리터럴(`\ ` 등)이 있을 경우 의도한 대로 동작하지 않을 수 있습니다. 만약 읽은 토큰이 정규 표현식을 만족하지 않는다면 `_wa` 결과로 종료합니다. 242 | 243 | Strict mode에서는 공백을 무시하지 않으며, 토큰과 토큰 사이에는 무조건 한 개의 띄어쓰기(` ` = 32)가 있어야 하고, 띄어쓰기 이외의 공백 문자는 허용되지 않습니다. 현재 위치가 공백 문자임에도 불구하고 `readTokens`을 수행하는 경우, 또는 토큰이 띄어쓰기 한 개보다 많은 수의 공백 문자로 구분된 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 244 | 245 | Validator에서 `inf`의 입력을 검증하는 경우, `ptrn`, `p`와 `variableNames`를 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 246 | 247 | ### InStream::readTokenTo 248 | 249 | - `void readTokenTo(std::string &result)` 250 | - `void readTokenTo(std::string &result, const pattern &p, const std::string &variableName = "")` 251 | - `void readTokenTo(std::string &result, const std::string &ptrn, const std::string &variableName = "")` 252 | - out `result`: 읽은 토큰. 253 | - `ptrn`, `p`: 입력 검증에 사용할 정규 표현식. 254 | - `variableName`: 변수 이름. 255 | 256 | [readToken](#instreamreadtoken)과 같은 동작으로 토큰을 읽습니다. 단, 읽은 토큰은 반환되는 대신 `result`에 저장됩니다. 257 | 258 | Validator에서 `inf`의 입력을 검증하는 경우, `ptrn`, `p`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 259 | 260 | ### InStream::readWord 261 | 262 | - `std::string readWord()` 263 | - `std::string readWord(const std::string &ptrn, const std::string &variableName = "")` 264 | - `std::string readWord(const pattern &p, const std::string &variableName = "")` 265 | 266 | = [readToken](#instreamreadtoken). 267 | 268 | ### InStream::readWords 269 | 270 | - `std::vector readWords(int size, int indexBase = 1)` 271 | - `std::vector readWords(int size, const std::string &ptrn, const std::string &variablesName = "", int indexBase = 1)` 272 | - `std::vector readWords(int size, const pattern &p, const std::string &variablesName = "", int indexBase = 1)` 273 | 274 | = [readTokens](#instreamreadtokens). 275 | 276 | ### InStream::readWordTo 277 | 278 | - `void readWordTo(std::string &result)` 279 | - `void readWordTo(std::string &result, const std::string &ptrn, const std::string &variableName = "")` 280 | - `void readWordTo(std::string &result, const pattern &p, const std::string &variableName = "")` 281 | 282 | = [readTokenTo](#instreamreadtokento). 283 | 284 | ### InStream::readLine 285 | 286 | - `std::string readLine()` 287 | - `std::string readLine(const std::string &ptrn, const std::string &variableName = "")` 288 | - `std::string readLine(const pattern &p, const std::string &variableName = "")` 289 | - `ptrn`, `p`: 입력 검증에 사용할 정규 표현식. 290 | - `variableName`: 변수 이름. 291 | 292 | 현재 위치부터 다음 개행 시퀀스 이전까지의 문자열을 읽습니다. 공백을 무시하지 않습니다. 개행 시퀀스는 읽지 않으며, 커서는 개행 시퀀스의 첫 문자 위치로 이동합니다. 293 | 294 | `ptrn` 혹은 `p`를 명시하는 경우, 명시된 [정규 표현식](./pattern.md)을 만족하는 토큰을 읽습니다. 정규 표현식에 개행 문자 리터럴(`\n` 등)이 있을 경우 의도한 대로 동작하지 않을 수 있습니다. 만약 읽은 토큰이 정규 표현식을 만족하지 않는다면 `_wa` 결과로 종료합니다. 295 | 296 | Strict mode에서는 개행 시퀀스는 여전히 읽지 않지만, 커서는 개행 시퀀스 **이후**의 첫 문자 위치로 이동합니다. Strict mode에서는 Windows 환경일 경우에는 `\r\n`만을 개행 시퀀스로 보며, 그렇지 않은 환경일 경우에는 `\n`만을 개행 시퀀스로 봅니다. 297 | 298 | Validator에서 `inf`의 입력을 검증하는 경우, `ptrn`, `p`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 299 | 300 | ### InStream::readLines 301 | 302 | - `std::vector readLines(int size, int indexBase = 1)` 303 | - `std::vector readLines(int size, const std::string &ptrn, const std::string &variablesName = "", int indexBase = 1)` 304 | - `std::vector readLines(int size, const pattern &p, const std::string &variablesName = "", int indexBase = 1)` 305 | - `size`: 읽을 토큰의 개수. 306 | - `ptrn`, `p`: 입력 검증에 사용할 정규 표현식. 307 | - `variablesName`: 변수 이름. 308 | - `indexBase`: 입력 오류 시 출력할 인덱스의 시작 값. 309 | 310 | 현재 위치부터 개행 시퀀스로 구분된 `size`개의 문자열, 즉 지금 위치로부터 `size`개 줄을 읽습니다. 공백을 무시하지 않습니다. 개행 시퀀스는 읽지 않으며, 커서는 마지막 개행 시퀀스의 첫 문자 위치로 이동합니다. 311 | 312 | `ptrn` 혹은 `p`를 명시하는 경우, 명시된 [정규 표현식](./pattern.md)을 만족하는 토큰을 읽습니다. 정규 표현식에 개행 문자 리터럴(`\n` 등)이 있을 경우 의도한 대로 동작하지 않을 수 있습니다. 만약 읽은 토큰이 정규 표현식을 만족하지 않는다면 `_wa` 결과로 종료합니다. 313 | 314 | Strict mode에서는 개행 시퀀스는 여전히 읽지 않지만, 커서는 마지막 개행 시퀀스 **이후**의 첫 문자 위치로 이동합니다. Strict mode에서는 Windows 환경일 경우에는 `\r\n`만을 개행 시퀀스로 보며, 그렇지 않은 환경일 경우에는 `\n`만을 개행 시퀀스로 봅니다. 315 | 316 | Validator에서 `inf`의 입력을 검증하는 경우, `ptrn`, `p`와 `variableNames`를 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 317 | 318 | ### InStream::readLineTo 319 | 320 | - `void readLineTo(std::string &result)` 321 | - `void readLineTo(std::string &result, const std::string &ptrn, const std::string &variableName = "")` 322 | - `void readLineTo(std::string &result, const pattern &p, const std::string &variableName = "")` 323 | - out `result`: 읽은 토큰. 324 | - `ptrn`, `p`: 입력 검증에 사용할 정규 표현식. 325 | - `variableName`: 변수 이름. 326 | 327 | [readLine](#instreamreadline)과 같은 동작으로 토큰을 읽습니다. 단, 읽은 토큰은 반환되는 대신 `result`에 저장됩니다. 328 | 329 | Validator에서 `inf`의 입력을 검증하는 경우, `ptrn`, `p`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 330 | 331 | ### InStream::readString 332 | 333 | - `std::string readString()` 334 | - `std::string readString(const std::string &ptrn, const std::string &variableName = "")` 335 | - `std::string readString(const pattern &p, const std::string &variableName = "")` 336 | 337 | = [readLine](#instreamreadline). 338 | 339 | ### InStream::readStrings 340 | 341 | - `std::vector readStrings(int size, int indexBase = 1)` 342 | - `std::vector readStrings(int size, const std::string &ptrn, const std::string &variablesName = "", int indexBase = 1)` 343 | - `std::vector readStrings(int size, const pattern &p, const std::string &variablesName = "", int indexBase = 1)` 344 | 345 | = [readLines](#instreamreadlines). 346 | 347 | ### InStream::readStringTo 348 | 349 | - `void readStringTo(std::string &result)` 350 | - `void readStringTo(std::string &result, const std::string &ptrn, const std::string &variableName = "")` 351 | - `void readStringTo(std::string &result, const pattern &p, const std::string &variableName = "")` 352 | 353 | = [readLineTo](#instreamreadlineto). 354 | 355 | ## 정수 356 | 357 | 정수는 0을 제외하고서는 `0`으로 시작할 수 없습니다. 음수의 경우에도 `-0`으로 시작할 수 없습니다. 십진수 표현만 허용되며, 과학적 표기법, 예를 들어 `1e8` 등은 허용되지 않습니다. 만약 읽은 정수가 명시한 제한을 만족하지 않는다면 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 358 | 359 | ### InStream::readInt 360 | 361 | - `int readInt()` 362 | - `int readInt(int minv, int maxv, const std::string &variableName = "")` 363 | - `minv`, `maxv`: 읽을 정수의 범위. 364 | - `variableName`: 변수 이름. 365 | 366 | 공백 문자로 구분된 32비트 십진 정수를 읽습니다. 공백은 무시합니다. 커서는 정수의 마지막 문자 이후로 이동합니다. 367 | 368 | `minv`와 `maxv`를 명시하는 경우, $\texttt{minv} \le x \le \texttt{maxv}$를 만족하는 32비트 십진 정수 $x$를 읽습니다. 만약 읽은 정수가 명시한 범위를 만족하지 않는다면 `_wa` 결과로 종료합니다. 369 | 370 | Strict mode에서는 공백을 무시하지 않으며, 현재 위치가 공백임에도 불구하고 `readInt`을 수항하는 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 371 | 372 | Validator에서 `inf`의 입력을 검증하는 경우, `minv`, `maxv`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 373 | 374 | (TODO: InStream 메서드 설명) 375 | 376 | ### InStream::readInts 377 | 378 | - `std::vector readInts(int size, int indexBase = 1)` 379 | - `std::vector readInts(int size, int minv, int maxv, const std::string &variablesName = "", int indexBase = 1)` 380 | - `size`: 읽을 정수의 개수. 381 | - `minv`, `maxv`: 읽을 정수들의 범위. 382 | - `variablesName`: 변수 이름. 383 | - `indexBase`: 입력 오류 시 출력할 인덱스의 시작 값. 384 | 385 | 공백으로 구분된 32비트 정수 `size`개를 읽습니다. 정수와 정수 사이에 공백이 여러 개 있어도 되며, 이 경우 연속된 여러 개의 공백을 하나의 구분자로 봅니다. 커서는 `size`번째 정수의 마지막 문자 이후로 이동합니다. 386 | 387 | `minv`와 `maxv`를 명시하는 경우, $\texttt{minv} \le x \le \texttt{maxv}$를 만족하는 32비트 십진 정수 $x$를 `size`개 읽습니다. 만약 읽은 정수들 중 하나라도 명시한 범위를 만족하지 않는다면 `_wa` 결과로 종료합니다. 388 | 389 | Strict mode에서는 공백을 무시하지 않으며, 토큰과 토큰 사이에는 무조건 한 개의 띄어쓰기(` ` = 32)가 있어야 하고, 띄어쓰기 이외의 공백 문자는 허용되지 않습니다. 현재 위치가 공백 문자임에도 불구하고 `readInts`을 수행하는 경우, 또는 토큰이 띄어쓰기 한 개보다 많은 수의 공백 문자로 구분된 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 390 | 391 | Validator에서 `inf`의 입력을 검증하는 경우, `minv`, `maxv`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 392 | 393 | ### InStream::readInteger 394 | 395 | - `int readInteger()` 396 | - `int readInteger(int minv, int maxv, const std::string &variableName = "")` 397 | 398 | = [readInt](#instreamreadint). 399 | 400 | ### InStream::readIntegers 401 | 402 | - `std::vector readIntegers(int size, int indexBase = 1)` 403 | - `std::vector readIntegers(int size, int minv, int maxv, const std::string &variablesName = "", int indexBase = 1)` 404 | 405 | = [readInts](#instreamreadints). 406 | 407 | ### InStream::readLong 408 | 409 | - `long long readLong()` 410 | - `long long readLong(long long minv, long long maxv, const std::string &variableName = "")` 411 | - `minv`, `maxv`: 읽을 정수의 범위. 412 | - `variableName`: 변수 이름. 413 | 414 | 공백 문자로 구분된 64비트 십진 정수를 읽습니다. 공백은 무시합니다. 커서는 정수의 마지막 문자 이후로 이동합니다. 415 | 416 | `minv`와 `maxv`를 명시하는 경우, $\texttt{minv} \le x \le \texttt{maxv}$를 만족하는 64비트 십진 정수 $x$를 읽습니다. 만약 읽은 정수가 명시한 범위를 만족하지 않는다면 `_wa` 결과로 종료합니다. 417 | 418 | Strict mode에서는 공백을 무시하지 않으며, 현재 위치가 공백임에도 불구하고 `readLong`을 수항하는 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 419 | 420 | Validator에서 `inf`의 입력을 검증하는 경우, `minv`, `maxv`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 421 | 422 | ### InStream::readLongs 423 | 424 | - `std::vector readLongs(int size, int indexBase = 1)` 425 | - `std::vector readLongs(int size, long long minv, long long maxv, const std::string &variablesName = "", int indexBase = 1)` 426 | - `size`: 읽을 정수의 개수. 427 | - `minv`, `maxv`: 읽을 정수들의 범위. 428 | - `variablesName`: 변수 이름. 429 | - `indexBase`: 입력 오류 시 출력할 인덱스의 시작 값. 430 | 431 | 공백으로 구분된 64비트 정수 `size`개를 읽습니다. 정수와 정수 사이에 공백이 여러 개 있어도 되며, 이 경우 연속된 여러 개의 공백을 하나의 구분자로 봅니다. 커서는 `size`번째 정수의 마지막 문자 이후로 이동합니다. 432 | 433 | `minv`와 `maxv`를 명시하는 경우, $\texttt{minv} \le x \le \texttt{maxv}$를 만족하는 64비트 십진 정수 $x$를 `size`개 읽습니다. 만약 읽은 정수들 중 하나라도 명시한 범위를 만족하지 않는다면 `_wa` 결과로 종료합니다. 434 | 435 | Strict mode에서는 공백을 무시하지 않으며, 토큰과 토큰 사이에는 무조건 한 개의 띄어쓰기(` ` = 32)가 있어야 하고, 띄어쓰기 이외의 공백 문자는 허용되지 않습니다. 현재 위치가 공백 문자임에도 불구하고 `readLongs`을 수행하는 경우, 또는 토큰이 띄어쓰기 한 개보다 많은 수의 공백 문자로 구분된 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 436 | 437 | Validator에서 `inf`의 입력을 검증하는 경우, `minv`, `maxv`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 438 | 439 | ### InStream::readUnsignedLong 440 | 441 | - `unsigned long long readUnsignedLong()` 442 | - `unsigned long long readUnsignedLong(unsigned long long minv, unsigned long long maxv, const std::string &variableName = "")` 443 | - `minv`, `maxv`: 읽을 정수의 범위. 444 | - `variableName`: 변수 이름. 445 | 446 | 공백 문자로 구분된 부호 없는 64비트 십진 정수를 읽습니다. 공백은 무시합니다. 커서는 정수의 마지막 문자 이후로 이동합니다. 447 | 448 | `minv`와 `maxv`를 명시하는 경우, $\texttt{minv} \le x \le \texttt{maxv}$를 만족하는 부호 없는 64비트 십진 정수 $x$를 읽습니다. 만약 읽은 정수가 명시한 범위를 만족하지 않는다면 `_wa` 결과로 종료합니다. 449 | 450 | Strict mode에서는 공백을 무시하지 않으며, 현재 위치가 공백임에도 불구하고 `readUnsignedLong`을 수항하는 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 451 | 452 | Validator에서 `inf`의 입력을 검증하는 경우, `minv`, `maxv`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 453 | 454 | ### InStream::readUnsignedLongs 455 | 456 | - `std::vector readUnsignedLongs(int size, int indexBase = 1)` 457 | - `std::vector readUnsignedLongs(int size, unsigned long long minv, unsigned long long maxv, const std::string &variablesName = "", int indexBase = 1)` 458 | - `size`: 읽을 정수의 개수. 459 | - `minv`, `maxv`: 읽을 정수들의 범위. 460 | - `variablesName`: 변수 이름. 461 | - `indexBase`: 입력 오류 시 출력할 인덱스의 시작 값. 462 | 463 | 공백으로 구분된 부호 없는 64비트 정수 `size`개를 읽습니다. 정수와 정수 사이에 공백이 여러 개 있어도 되며, 이 경우 연속된 여러 개의 공백을 하나의 구분자로 봅니다. 커서는 `size`번째 정수의 마지막 문자 이후로 이동합니다. 464 | 465 | `minv`와 `maxv`를 명시하는 경우, $\texttt{minv} \le x \le \texttt{maxv}$를 만족하는 부호 없는 64비트 십진 정수 $x$를 `size`개 읽습니다. 만약 읽은 정수들 중 하나라도 명시한 범위를 만족하지 않는다면 `_wa` 결과로 종료합니다. 466 | 467 | Strict mode에서는 공백을 무시하지 않으며, 토큰과 토큰 사이에는 무조건 한 개의 띄어쓰기(` ` = 32)가 있어야 하고, 띄어쓰기 이외의 공백 문자는 허용되지 않습니다. 현재 위치가 공백 문자임에도 불구하고 `readUnsignedLongs`을 수행하는 경우, 또는 토큰이 띄어쓰기 한 개보다 많은 수의 공백 문자로 구분된 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 468 | 469 | Validator에서 `inf`의 입력을 검증하는 경우, `minv`, `maxv`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 470 | 471 | ## 실수 472 | 473 | 실수 입력 함수들은 공통적으로 실수를 입력받은 후 가장 가까운 `double` 값으로 반올림합니다. 따라서, 아래와 같은 코드를 작성하더라도 입력받은 수의 정확도는 `double`임에 주의합니다. 474 | 475 | ```cpp 476 | long double x = readDouble(); 477 | ``` 478 | 479 | ### InStream::readDouble 480 | 481 | - `double readDouble()` 482 | - `double readDouble(double minv, double maxv, const std::string &variableName = "")` 483 | - `minv`, `maxv`: 읽을 실수의 범위. 484 | - `variableName`: 변수 이름. 485 | 486 | 공백 문자로 구분된 실수를 읽습니다. 공백은 무시합니다. 커서는 실수의 마지막 문자 이후로 이동합니다. 487 | 488 | 실수는 C의 `%lf`로 입력받을 수 있는 형식 중 숫자가 한 개 이상 등장하는 형식만을 허용합니다. 과학적 표기법, 예를 들어 `3.1415e2` 등은 **허용됩니다**. 실수의 형식이 올바르지 않다면 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 허용되는 예는 다음과 같습니다. 489 | 490 | - `2` 491 | - `3.14` 492 | - `-1.8e6` 493 | - `.005` 494 | 495 | `minv`와 `maxv`를 명시하는 경우, $\texttt{minv}\_\mathbb{F} \le x \le \texttt{maxv}\_\mathbb{F}$를 만족하는 실수 $x$를 읽습니다. 만약 읽은 실수가 명시한 범위를 만족하지 않는다면 `_wa` 결과로 종료합니다. 496 | 497 | Strict mode에서는 공백을 무시하지 않으며, 현재 위치가 공백임에도 불구하고 `readDouble`을 수항하는 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 498 | 499 | Validator에서 `inf`의 입력을 검증하는 경우, [`readStrictDouble`](#instreamreadstrictdouble)를 사용하는 것을 권장합니다. `readDouble`을 사용할 경우,`minv`, `maxv`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 500 | 501 | ### InStream::readDoubles 502 | 503 | - `std::vector readDoubles(int size, int indexBase = 1)` 504 | - `std::vector readDoubles(int size, double minv, double maxv, const std::string &variablesName = "", int indexBase = 1)` 505 | - `size`: 읽을 실수의 개수. 506 | - `minv`, `maxv`: 읽을 실수들의 범위. 507 | - `variablesName`: 변수 이름. 508 | - `indexBase`: 입력 오류 시 출력할 인덱스의 시작 값. 509 | 510 | 공백으로 구분된 실수 `size`개를 읽습니다. 실수와 실수 사이에 공백이 여러 개 있어도 되며, 이 경우 연속된 여러 개의 공백을 하나의 구분자로 봅니다. 커서는 `size`번째 실수의 마지막 문자 이후로 이동합니다. 511 | 512 | 실수는 C의 `%lf`로 입력받을 수 있는 형식 중 숫자가 한 개 이상 등장하는 형식만을 허용합니다. 과학적 표기법, 예를 들어 `3.1415e2` 등은 **허용됩니다**. 실수의 형식이 올바르지 않다면 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 허용되는 예는 다음과 같습니다. 513 | 514 | - `2` 515 | - `3.14` 516 | - `-1.8e6` 517 | - `.005` 518 | 519 | `minv`와 `maxv`를 명시하는 경우, $\texttt{minv}\_\mathbb{F} \le x \le \texttt{maxv}\_\mathbb{F}$를 만족하는 실수 $x$를 `size`개 읽습니다. 만약 읽은 실수들 중 하나라도 명시한 범위를 만족하지 않는다면 `_wa` 결과로 종료합니다. 520 | 521 | Strict mode에서는 공백을 무시하지 않으며, 토큰과 토큰 사이에는 무조건 한 개의 띄어쓰기(` ` = 32)가 있어야 하고, 띄어쓰기 이외의 공백 문자는 허용되지 않습니다. 현재 위치가 공백 문자임에도 불구하고 `readDoubles`을 수행하는 경우, 또는 토큰이 띄어쓰기 한 개보다 많은 수의 공백 문자로 구분된 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 522 | 523 | Validator에서 `inf`의 입력을 검증하는 경우, [`readStrictDoubles`](#instreamreadstrictdoubles)를 사용하는 것을 권장합니다. `readDoubles`를 사용할 경우, `minv`, `maxv`와 `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 524 | 525 | ### InStream::readReal 526 | 527 | - `double readReal()` 528 | - `double readReal(double minv, double maxv, const std::string &variableName = "")` 529 | 530 | = [readDouble](#instreamreaddouble). 531 | 532 | ### InStream::readReals 533 | 534 | - `std::vector readReals(int size, int indexBase = 1)` 535 | - `std::vector readReals(int size, double minv, double maxv, const std::string &variablesName = "", int indexBase = 1)` 536 | 537 | = [readDoubles](#instreamreaddoubles). 538 | 539 | ### InStream::readStrictDouble 540 | 541 | - `double readStrictDouble(double minv, double maxv, int minAfterPointDigitCount, int maxAfterPointDigitCount, const std::string &variableName = "")` 542 | - `minv`, `maxv`: 읽을 실수의 범위. 543 | - `minAfterPointDigitCount`, `maxAfterPointDigitCount`: 읽을 실수의 소수점 이하 자릿수의 범위. 544 | - `variableName`: 변수 이름. 545 | 546 | 공백 문자로 구분된 실수를 읽습니다. 공백은 무시합니다. 커서는 실수의 마지막 문자 이후로 이동합니다. 547 | 548 | 실수는 `[0-9]*(\.[0-9]+)?` 형태여야 하며, 소숫점 이하에 $\left[\texttt{minAfterPointDigitCount}, \texttt{maxAfterPointDigitCount}\right]$개의 숫자를 가져야 합니다. 과학적 표기법, 예를 들어 `3.1415e2` 등은 **허용되지 않으며**, 첫 글자가 소수점인 경우도 허용되지 않습니다. 실수의 형식이 올바르지 않다면 [`_pe`](tresult.md#_pe) 결과로 종료합니다. [readDouble](#instreamreaddouble)과 입력 형식이 다름에 주의하며, 입력 함수는 소수점 이하 숫자의 수에 제한을 걸 뿐 소수점 이하 숫자의 수가 일정 이상 많아져도 `double`의 정밀도를 넘어서는 경우의 정밀도를 보장하지는 않음에 주의합니다. 549 | 550 | `minv`와 `maxv`를 명시하는 경우, $\texttt{minv}\_\mathbb{F} \le x \le \texttt{maxv}\_\mathbb{F}$를 만족하는 실수 $x$를 읽습니다. 만약 읽은 실수가 명시한 범위를 만족하지 않는다면 `_wa` 결과로 종료합니다. 551 | 552 | Strict mode에서는 공백을 무시하지 않으며, 현재 위치가 공백임에도 불구하고 `readStrictDouble`을 수항하는 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 553 | 554 | Validator에서 `inf`의 입력을 검증하는 경우, `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 555 | 556 | ### InStream::readStrictDoubles 557 | 558 | - `std::vector readStrictDoubles(int size, double minv, double maxv, int minAfterPointDigitCount, int maxAfterPointDigitCount, const std::string &variablesName = "", int indexBase = 1)` 559 | - `size`: 읽을 실수의 개수. 560 | - `minv`, `maxv`: 읽을 실수들의 범위. 561 | - `minAfterPointDigitCount`, `maxAfterPointDigitCount`: 읽을 실수의 소수점 이하 자릿수의 범위. 562 | - `variablesName`: 변수 이름. 563 | - `indexBase`: 입력 오류 시 출력할 인덱스의 시작 값. 564 | 565 | 공백으로 구분된 실수 `size`개를 읽습니다. 실수와 실수 사이에 공백이 여러 개 있어도 되며, 이 경우 연속된 여러 개의 공백을 하나의 구분자로 봅니다. 커서는 `size`번째 실수의 마지막 문자 이후로 이동합니다. 566 | 567 | 실수는 `[0-9]*(\.[0-9]+)?` 형태여야 하며, 소숫점 이하에 $\left[\texttt{minAfterPointDigitCount}, \texttt{maxAfterPointDigitCount}\right]$개의 숫자를 가져야 합니다. 과학적 표기법, 예를 들어 `3.1415e2` 등은 **허용되지 않으며**, 첫 글자가 소수점인 경우도 허용되지 않습니다. 실수의 형식이 올바르지 않다면 [`_pe`](tresult.md#_pe) 결과로 종료합니다. [readDoubles](#instreamreaddoubles)과 입력 형식이 다름에 주의하며, 입력 함수는 소수점 이하 숫자의 수에 제한을 걸 뿐 소수점 이하 숫자의 수가 일정 이상 많아져도 `double`의 정밀도를 넘어서는 경우의 정밀도를 보장하지는 않음에 주의합니다. 568 | 569 | `minv`와 `maxv`를 명시하는 경우, $\texttt{minv}\_\mathbb{F} \le x \le \texttt{maxv}\_\mathbb{F}$를 만족하는 실수 $x$를 `size`개 읽습니다. 만약 읽은 실수들 중 하나라도 명시한 범위를 만족하지 않는다면 `_wa` 결과로 종료합니다. 570 | 571 | Strict mode에서는 공백을 무시하지 않으며, 토큰과 토큰 사이에는 무조건 한 개의 띄어쓰기(` ` = 32)가 있어야 하고, 띄어쓰기 이외의 공백 문자는 허용되지 않습니다. 현재 위치가 공백 문자임에도 불구하고 `readStrictDoubles`을 수행하는 경우, 또는 토큰이 띄어쓰기 한 개보다 많은 수의 공백 문자로 구분된 경우 [`_pe`](tresult.md#_pe) 결과로 종료합니다. 572 | 573 | Validator에서 `inf`의 입력을 검증하는 경우, `variableName`을 명시하여야 합니다. 명시하지 않은 경우 Polygon에서 패키지 경고가 발생합니다. 574 | 575 | ### InStream::readStrictReal 576 | 577 | - `double readStrictReal(double minv, double maxv, int minAfterPointDigitCount, int maxAfterPointDigitCount, const std::string &variableName = "")` 578 | 579 | = [readStrictDouble](#instreamreadstrictdouble). 580 | 581 | ### InStream::readStrictReals 582 | 583 | - `std::vector readStrictReals(int size, double minv, double maxv, int minAfterPointDigitCount, int maxAfterPointDigitCount, const std::string &variablesName = "", int indexBase = 1)` 584 | 585 | = [readStrictDoubles](#instreamreadstrictdoubles). 586 | --------------------------------------------------------------------------------