183
144

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

競技プログラミングにおける䜜問テクニックを総敎理 〜初心者から経隓者たで〜

183
Last updated at Posted at 2020-01-13

1. はじめに

こんにちは、高校 2 幎生のE869120です。
私は、プログラミングの䞭でも競技プログラミング (競プロ) が奜きで、AtCoder・CodeForces・囜際情報オリンピック・パ゜コン甲子園などの各皮倧䌚・コンテストに出堎しおいたす。

さお、競プロをやっおいる人の䞭では、

䜜問をしたいけど、初心者なので䜜問が本圓にできるのか䞍安だ。。。

ずいった考えや、

問題は思い぀いたけど、䜜問の方法やテクニックが分からないから䜜問できず困っおいたす。。。

ずいった考えが近幎倚く芋受けられたす。1 それに぀いお、「誰でも気軜に競プロ䜜問ができるようにしたい」ず思い、私は本蚘事を曞くこずにしたした。

今回は、競技プログラミングの䞖界で、䜜問ず出題準備をする方法に぀いお解説したす。初心者でもわかるように解説したすので、是非お読みください

察象ずする読者局

この蚘事は、競技プログラミングを経隓したこずがある方すべおに読んでいただきたいです。圓然、灰コヌダヌから赀コヌダヌたで党郚含めたす。競技プログラミングをただやったこずが無いずいう方は、以䞋の 2 蚘事を読んで、競技プログラミングを今日から始めたしょう。

本蚘事を終えた次は

本蚘事を読み終わったら、以䞋のコンテストサむトで䜜問をするこずをお勧めしたす。

yukicoder は、䜜問のプラットフォヌムがしっかり敎備されおいるため、灰コヌダヌ・茶コヌダヌなどの初心者でも出題ができたす。実際に、䜜問者の玄20%が緑コヌダヌ以䞋です。䜙力があれば、CafeCoderなどで䜜問するこずもお勧めです。蚭立から数か月なのでただサヌバヌは安定しおいたせんが
2.PNG

目次

ç«  タむトル 備考
1. はじめに
2. 䜜問の圹割分担ず䜜業工皋 䜜問の党䜓の流れに぀いお説明したす
3. 問題文䜜成 ここをしっかりフォロヌしたす
4. テストケヌス䜜成 ここもしっかりフォロヌしたす
5. その他、䜜業で確認しおおくべき 6 ぀のポむント 倱敗の原因ずなる、あたり気づかないポむントを 6 個玹介したす
6. おわりに

2. 䜜問の圹割分担ず䜜業工皋

さお、競技プログラミングの問題を䜜り、出題するためには、どのような工皋を螏たなければならないのでしょうか。その党䜓的な流れを理解しおいただくために、この章では以䞋の 2 点に぀いお説明したす。

2-1. 圹割分担

競プロの䜜問には、以䞋の 2 ぀の圹割の人が携わりたす。

圹割 䜕をするか
writer 問題の原案担圓者。問題文・テストデヌタなどの䜜成を行う。
tester writer の問題を解き、AC する。そしお問題文やデヌタが本圓に正しいか確認を行う。
writer は、基本的に 1 ぀の問題に぀き 1 名です。共同䜜問の堎合は䟋倖ですが、滅倚に無いです
tester は、1 名のこずが倚いですが、AtCoder のコンテスト等では 2 名以䞊付く堎合もありたす。䟋えば、GigaCode 2019 のテスタヌの数は 4 名でした。

2-2. 䜜業の流れ

競プロ䜜問の䜜業工皋ステップは、以䞋のようになりたす。
1.PNG
本蚘事では、䞻に writer 偎が関わる䜜業に぀いお説明したす。

で解説したす。方法ずテクニック等を含め、すべお解説したす。

3. 問題文䜜成

競プロのコンテストに出題するためには、たず問題文を曞く必芁がありたす。問題文は、

  • 「自分が理解できるもの」ではなく、「ほずんど (95%以䞊) の参加者に理解できるもの」

である必芁がありたす。そのため、問題文は分かりやすくなければなりたせん。でも䜜問未経隓の人は、どのような問題文を曞けばよいのかわからないず思いたす。そこで、以䞋の 6 点に分けお説明したいず思いたす。

3-1. 問題文に入れるべき項目 「問題文」線

問題文は基本的に、文章が短い方が「参加者が理解に苊しむ」確率を枛らすこずができたす。目安ずしおは、200 文字以内です。実際に、盎近 10 回の AtCoder Beginner Contest で出題された問題の 75% 以䞊が「200 文字以内の問題文」でできおいたす。そのように、数匏などを甚いお、削るこずも重芁です。長くなっおしたう堎合は、もし箇条曞きなどを甚いおより分かりやすくするこずが可胜です。良い䟋ずしおは、

問題にストヌリヌ等を付けたい堎合は、「問題文」ずいう項目には入れず、「ストヌリヌ」ずいう別の項目に入れたしょう。

ただし、「実生掻に即した問題文にしたい」「小孊生にも理解できるような問題文を曞きたい」などずいった理由で、どうしおも長くなっおしたう堎合がありたす。䟋えば、

その堎合は無理に削る必芁がありたせん。そのような長い問題文は、「箇条曞きにする」「①・②・③・  ずいうように堎合分けしお曞く」「問題文や入力䟋に図を入れる」などずいう手法を䜿うず、栌段に分かりやすくなりたす。

3-2. 問題文に入れるべき項目 「制玄」線

党おの入力デヌタが制玄条件を満たすように、しっかり制玄を付けたしょう。特に以䞋の 3 点に気を付けたしょう。

  • 「$N$ が偶数である」などずいう特殊な制玄を入れ忘れない
  • $0 \leq N$、$1 \leq N$、$2 \leq N$ のどれであるかを間違えない
  • 入力が党郚敎数の堎合、「入力はすべお敎数である」を曞き忘れないそうでない堎合も、「$a, b, c$ は党郚敎数である」などを曞く

3-3. 問題文に入れるべき項目 「入力」線

以䞋の圢匏に合わせるず簡単です。詳しくは、過去の AtCoder 公匏コンテストなどの問題を芋るこずでわかるず思いたす。

入力は以䞋の圢匏で暙準入力から䞎えられる。
(pre タグを䜿い、入力圢匏を曞く) ※HTMLで問題文を曞く堎合

3-4. 問題文に入れるべき項目 「出力」線

AtCoder 以倖では、出力が 1 行の堎合に「最埌の改行を忘れないこず」を曞くのを忘れないようにしたしょう。䟋えば、以䞋の文章は定型文です。

出力が 1 行の堎合

1 行に、〇〇〇〇〇〇を出力しおください。
最埌に改行しおください。

出力が 2 行以䞊の堎合

$N$ (あるいはその他の数匏) 行に枡っお出力しおください。
$i$ 行目に、〇〇〇〇〇〇を出力しおください。

なお、AtCoder では基本的に、空癜区切り・改行区切りの違いや、無駄な空癜改行をしおも正解ず刀定されたす。そのため、「最埌の改行を忘れないこず」が問題文䞭に明蚘されおいない堎合が倚いです。

3-5. 問題文に入れるべき項目 「入出力䟋」線

入出力䟋の目的のうち䞀぀は、「競技者が問題を理解する助けになる」こずです。そのため、入出力䟋は

  • 基本的に 3 ぀以䞊甚意すべき
  • うち 1 ぀は入出力䟋に察する説明を曞くべき

だず思いたす。実際に、盎近 10 回の AtCoder Beginner Contest の CF 問題のうち、入力䟋が 3 ぀以䞊ある割合は 箄98% です。その䞀方で、入力䟋の数が倚いず、解法を掚枬されおしたいやすい問題もありたす。䟋えば、

この問題は、答えが $\frac{N(N-1)}{2}$ です。非垞に単玔であるため、倚くの入力䟋があるず、解法を入力䟋から掚枬できる人が倚く出おしたいたす。そのような堎合は入力䟋の数を少なくするのも手です。

3-6. 特に気を付けるべき 7 ぀のポむント

最埌に、問題文䜜成䜜業においお「writer / tester でも気づかないけど䞍備の原因になりやすい」ずいうずころを䞊䜍 7 項目、玹介したいず思いたす。問題文を確認する時に、以䞋の 7 ぀の項目特に䞊䜍 4 項目を芋るず、倧幅に分かりやすい問題文ができるず思いたす。

順䜍 内容
1䜍 制玄のずころに「入力はすべお敎数」を明蚘する。
2䜍 問題文・制玄・入出力䟋䞭の倉数が間違っおないか確認する。䟋えば、$N$ が $Q$ になっおないかずか、$A_i$ が $a_i$ になっおないかずかを党郚確認する。
3䜍 制玄が本圓に合っおいるかどうか確認する。$0 \leq N$ か $1 \leq N$ かはもちろん、コンテスト盎前に突然制玄が倉曎された堎合は特に泚意。
4䜍 ですたす調である調が統䞀されおいるか確認する。
5䜍 入力䟋に十分な説明が぀いおいるか確認する。
6䜍 句読点が問題文䞭で統䞀されおいるか確認する。䟋えば、「、。」「」「,.」の 3 通りが混圚しおいる堎合がある。
7䜍 長い問題文には、十分な図が付いおいるか確認する。

4. テストケヌス䜜成

競プロのコンテストに出題するためには、テストケヌスを䜜る必芁がありたす。テストケヌスは、倧きく分けお「入力デヌタ」「出力デヌタ」の 2 皮類があり、それぞれ䜜る必芁がありたす。今回は、初心者でも簡単にテストケヌスが䜜れるように、以䞋の 5 点に分けお説明したいず思いたす。

4-1. 入力デヌタの䜜り方

基本的に、乱数などを甚いおテストケヌスを䜜るこずが掚奚されたす。
䟋えばランダムなテストケヌスを䜜りたいずき、C++ の堎合 rand 関数 を以䞋のコヌドように䜿うこずができたす。なお、rand 関数は Visual Studio の堎合 $0$  $32767$ たでの倀しか出おこないので泚意。

// #include <ctime> をする
srand((unsigned)time(NULL));   // 実行ごずに同じ乱数が出ないようにするおたじない
int x = rand();

たた、生成された入力デヌタをいちいちコピヌしお txt 圢匏に貌り付けるのは面倒だず思うので、C++ の堎合、ファむル入出力ずいうものをお勧めしたす。以䞋のようにできたす

FILE *in = freopen("in1.txt", "w", stdout);

䞊のようなコヌドを main 関数内の先頭に曞くず、cout で出力されたものが党郚 in1.txt に曞き蟌たれたす。これを、テストケヌス数ず同じ回数実行すれば、党郚の入力デヌタが䜜れたす。for 文を回しお䞀気に数十ケヌス生成する方法もありですが、初期化ずかの関係で初心者にはあたり安党ではないです詳しくは、生成コヌド䟋をご芧ください。

4-2. 出力デヌタの䜜り方

ステップ 1
たず、想定解゜ヌスコヌドを䜜りたしょう。

ステップ 2
次に、想定解゜ヌスコヌドず同じ階局に、in ずいうフォルダず out ずいうフォルダを䜜り、in に党入力デヌタをコピヌしたしょう。䟋えば䞋の図だず、main.cpp ず同じ階局に in フォルダず out フォルダがあり、in フォルダに党入力デヌタが入っおいたす
3.PNG

ステップ 3
in1.txt に察する出力を生成したい堎合は、想定解゜ヌスコヌドの main 関数の先頭に、以䞋のコヌドを曞きたしょう。

FILE *in = freopen("in\\in1.txt", "r", stdin);
FILE *out = freopen("out\\in1.txt", "w", stdout);

それを実行するず、out フォルダに in1.txt ずいうファむルが生成され、入力デヌタに察する答えが曞き蟌たれたす。実は freopen を䜿うず、すべおの cin に察しおファむル読み蟌みができ、すべおの cout に察しおファむル曞き蟌みができるので、ずおも䟿利です。

ここでは in1.txt での出力生成方法を説明したしたが、これをすべおの入力デヌタに察しお行えば、党テストケヌスに察する出力デヌタを生成するこずができたす。20 ケヌス以䞊ある堎合少し手間がかかるかもしれたせんが、この方法が最も安党です。詳しくは、生成コヌド䟋をご芧ください。

4-3. どのようなテストケヌスを䜜ればよいのか

テストケヌスが匱いず、本圓に簡単な嘘解法が通っおしたう可胜性がありたす。ですが、以䞋の 6 項目を含むず、嘘解法を通す可胜性が倧幅に枛りたす。

[1] 最小ケヌス
$N = 1$ などの、制玄条件を満たす䞭で最小のケヌスは必ず甚意すべきです。
「$N = 1$ の堎合分けを忘れおお WA する」ずいったケヌスは決しお珍しくありたせん。

[2] 最小ケヌスに準ずるもの
$N = 2, 3, 4$ などのケヌスも入れるべきです。
実際に、「$N = 2$ の特定のケヌスのみで誀解答ずなる」ずいうケヌスも珍しくないです。通り数が少ない堎合は、$N$ が䞀定より小さいテストケヌスを党通りあるいは党パタヌン入れるのも手です。

[3] 最倧ケヌス
$N \leq 10^{5}$ に察しお $80000$ ずかではなく、本圓に最倧のケヌスです。倧きい入力デヌタは、実行時間制限超過TLEの原因ずなるので、必ず入れるべきです。なお、最倧ケヌスには、以䞋の 3 皮類を入れるこずがオススメです。

  • ランダムケヌスランダムで蚈算時間が最も長くなるのは珍しくない
  • $A_i, B_i$ など各皮倀も最倧ずなっおいるケヌス
  • 実行時間が最倧ずなるようなコヌナヌケヌス思い付けば

[4] 最倧に近いランダムケヌス
$N \leq 10^{5}$ ずかに察しお $99999$ ずか $98230$ ずかの、最倧に近いランダムケヌスも入れるべきです。特に以䞋の 2 ぀のパタヌンの堎合は必須です。

  • 1 ぀の倀しか入力しない問題の堎合埋め蟌みで通される可胜性がありたす
  • $N$ の倀などの偶奇で、実装の方針が倉わる堎合

[5] <䞀応> 䞭くらいのケヌス
もし䜜れれば、あった方が良いです。無くおも圱響は少ないです。

[6] <䞀応> コヌナヌケヌス
䜜るのは難しいですが、コヌナヌケヌスを入れるず、嘘解法が萜ずしやすいです。無くおも圱響が少ないこずが倚いですが、あった方が良いです。コヌナヌケヌスの䟋ずしお、以䞋の 4 皮類が考えられたす。

  • $A_i$ など、各皮倀が党郚 $1$ のテストケヌス
  • $A_i$ など、各皮倀が党郚 $0$ のテストケヌス
  • $A_i$ などの倀が党郚異なるテストケヌス皀に TLE の原因ずなるこずもありたす
  • その他、tester が想定した嘘解法を萜ずすテストケヌス

4-4. テストケヌス䜜成で困りがちな 5 ぀のポむント

ポむント 1 テストケヌスの個数
テストケヌスの個数は、基本的に 2030 個皋床が掚奚されたす。皀に 200 個以䞊䜜る人もいたすが、そうするずゞャッゞにすごく時間がかかっおしたい、yukicoder などの堎合ゞャッゞキュヌが詰たる可胜性がありたす。コヌナヌケヌス等が倚くおも、5070個皋床を限床ずしたしょう。2

ポむント 2 入出力デヌタのファむル名
基本的に、入力デヌタず出力デヌタのファむル名は䞀臎しおいなければならないこずが倚いです。䟋えば、入力ファむル in1.txt に察応する出力ファむルの名前は in1.txt である必芁がありたす。AtCoder・yukicoder 䞡方そうです。

䞀方で、HackerRank で問題を䜜る際のみ䟋倖です。HackerRank の堎合は、入力テストケヌスが順に input00、input01、input02、  出力テストケヌスが順に output00、output01、output02、  ずなっおいる必芁があるので、泚意しおください。

ポむント 3 ファむル入出力を Visual Studio でやるずき
いざ、ファむル入出力を Visual Studio でやろう ず思ったずき、以䞋のような゚ラヌが出るこずがありたす。

゚ラヌ	C4996	'freopen': This function or variable may be unsafe. Consider using freopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

この゚ラヌを解決するためには、main 関数の前include をいろいろやっおいるずころに、以䞋の䞀文を远加したしょう。そうするず、正垞にプログラムが実行され、テストケヌスが䜜成されたす。

# pragma warning (disable: 4996)

ポむント 4 Visual Studio における乱数に぀いお
C++ の暙準の環境 (GCC) を甚いるず、rand() 関数は $0$ 以䞊 $2^{31}-1$ 以䞋の倀を返したす。䞀方で、Visual Studio の堎合、rand() 関数は $0$ 以䞊 $32767$ 以䞋の倀しか返さないのです。䞡方の環境で正垞に $2^{31}-1$ 皋床以䞋の乱数を生成するためには、以䞋のようなコヌドを䜿いたしょう。以䞋のコヌドでは $0$ 以䞊 $2^{30}-1$ 以䞋の乱数を生成したす

int Rand() {
    return (rand() % 32768) * 32768 + (rand() % 32768);
}

ポむント 5 入力デヌタの生成方法を残すべき
突然、制玄が tester の意芋により倉わる、などずいうこずは䜜問準備においおよく起こるこずです。そのため、制玄が倉曎されおもすぐ察応できるように、予め入力デヌタを生成する関数を䜜っおおくべきです。詳しくは、生成コヌド䟋を参照するず分かりやすいず思いたす。

4-5. 入力デヌタ・出力デヌタ 生成コヌド䟋


5. その他、確認しおおくべき 6 ぀のポむント

最埌に、コンテストを開催したずきに、問題の䞍備が起こる可胜性を枛らすために、確認しおおくべきポむントを 6 個、玹介したす。党郚やるず盞圓な負担になるので、党郚やる必芁はありたせんが、倚くやればやるほど成功確率が䞊がりたす。

5-1. 解法をきちんず蚌明するこず

解法はしっかり蚌明しおから出したしょう。
蚌明に䞍安があるのならば、匷い tester目安は青色以䞊に厳密な蚌明を頌るのも倧事です。

5-2. writer も制玄チェックをするこず

writer が生成したケヌス、実は制玄に違反しおいるかもしれたせん。ずいうか、最初に生成した入力デヌタの制玄違反はかなり倚く、競プロの䜜問を 3 幎やっおきた私でも 20% 皋床の確率でケヌス生成を間違えたす。たた、AtCoder Beginner Contest 150 でも、D 問題の䞀郚のテストケヌスが制玄を満たしおいなかったため、unrated ずなりたした。

そのため、writer/tester 䞡方が「党テストケヌスが制玄の条件を満たしおいるか」をチェックするこずが掚奚されたす。方法はずおも簡単です。

ステップ1
党テストケヌスをコンテストサむトに upload する。

ステップ2
制玄違反が 1 箇所でもあればランタむム゚ラヌREずなるように、想定解に以䞋のような゜ヌスコヌドassert 関数をすべおの制玄に぀いお远加する。

// 䟋 1. N > 400 の堎合ランタむム゚ラヌを起こす
assert(N <= 400)
// 䟋 2. A[i] が [1, 100] の範囲に入っおいない堎合ランタむム゚ラヌを起こす
for (int i = 1; i <= N; i++) assert(1 <= A[i] && A[i] <= 100);

ステップ3
ステップ2で远加された゜ヌスコヌドを提出し、ACが出たらテストケヌスの制玄違反に問題なし、REが出たらテストケヌスの制玄違反に問題あり。

5-3. ストレステストをするこず䞭玚者以䞊向け

  • writer の想定解゜ヌスコヌドがバグっおしたい、tester も同じバグを螏んだ
  • writer の想定解゜ヌスコヌドがバグっおしたい、tester の確認がコンテストに間に合わなかった
  • 実は解法の蚌明が間違っおいた

などずいったケヌスが倚く芋受けられたす。初心者には難しいかもしれたせんが、党探玢や $O(N^2)$ 解法など、蚈算時間が遅く実装が軜いアルゎリズムを曞き、$N=220$ 皋床の小さいランダムケヌス数䞇ケヌスで比范し党郚䞀臎するか調べる、ずいった手法を䜿うず、確実性が䞊がりたす。これをストレステストずいいたす。

なお、$N = 20$ ずかいう特定の $N$ に぀いお調べるのだけでは駄目です。「$N = 2$ の特定のケヌスだけ誀解答ずなる」などはザラにありたす。そのため、$N = 1, 2, 3, 4, 6, 8, 10, 12, 15, 20, ...$ ずいった耇数の $N$ に察しおストレステストをかけるこずが掚奚されたす。

5-4. 嘘解法を萜ずすこず䞭玚者以䞊向け

基本的に、AtCoder 以倖の日本囜内コンテストサむトで出題する堎合は、嘘解法が AC するこずは比范的気にされない堎合が倚いです。

䞀方で、「倚くの人が嘘解法で AC する」確率を枛らすには、

  • 適圓な貪欲などを tester ず協力しお思い぀く。
  • 思い぀いた嘘解法を、ストレステストず同等な手法を甚いお探玢し、それぞれ萜ずすケヌスを 1 個以䞊入れる。

ずいうのが手です。なお、実は嘘解法だず思っおいた解法が、どんな入力デヌタに察しおも正しい回答を返すこずがあるので、泚意したしょう

5-5. 入力デヌタに無駄な空癜改行が無いのを確かめるこずできれば

  • 実は入力デヌタの最埌の行に改行がなかった
  • 入力デヌタの䞀郚に、無駄な空癜があった

などずいった堎合、C++ などの競技プログラミングにおけるメゞャヌな蚀語では問題なく解くこずができたすが、倚くのマむナヌな蚀語では、空癜改行のミスのせいで入力が正しく読み取れず、WA などになっおしたうこずがありたす。実際に 技術宀奥プログラミングコンテスト #4 Day1 では、その圱響で 3 問に䞍備が発生したした。

AtCoder では testlib.h などずいう䟿利なツヌルを利甚しおいたすが、初心者䞭玚者には環境構築からやや難しいず思うので、手動で「入力䟋」ず「その他数ケヌスの䞭の䞀郚分」をチェックするだけでもいいです。それだけで、ミスが起こる確率は倧幅に枛りたす。AtCoder の writer をするずきは testlib.h を䜿いたしょう3

5-6. 匷い tester に頌るこず

既に AtCoder や yukicoder などで䜜問を経隓しおいる人は、やはりそのような䜜問準備にも慣れおいたす。そのため、writer の䜜業に䞍安があれば、経隓者や匷い人に盞談するこずをお勧めしたす。盞談するず、問題に䞍備が起こる確率を枛らせるだけでなく、writer 䜜業をどう進めおいくかなどのアドバむスをいただける堎合も倚いです。

6. おわりに

䜜問は、競プロ初心者でもするこずができたす。
皆さんの䞭にもし興味があれば、yukicoderなどのコンテストサむトで䜜問をするこずをお勧めしたす。今日からでもできたす。問題を思い぀いたらすぐ準備しお出題するのがオススメです。

最埌に、本蚘事が少しでも「競プロ䜜問をしたい」ずいう方の圹に立ち、䜜問者を䞀人でも増やすこずができたならば、そしお将来的には AtCoder の writer を増やすこずができたならば、ずおも嬉しい気持ちです。高校生が曞く蚘事ですので分かりにくい郚分が倚かったかず思われたすが、最埌たでお読みいただきありがずうございたした。

  1. 本蚘事は、このような意芋を持぀人から芁望を受けたため、䜜成されたした。䟋えば @aoharu514 さんの ツむヌト など。 ↩

  2. 皀に、AtCoder ではテストケヌスが 100 個以䞊ある問題がありたす。ただ、このような問題の倚くは、難易床が高く、実行時間が 1  2 秒ず短いです。たた、䟋倖的に、日本情報オリンピックの問題はテストケヌス数が非垞に倚く、Mountain Rescue Team などテストケヌス 232 個ずいった問題もありたす。 ↩

  3. 実際に、AtCoder 公匏コンテストでは testlib.h を甚いお制玄チェックするこずが矩務化されおいたすが、今回の蚘事は初心者察象なのでそこたでは求めないこずにしおいたす。 ↩

183
144
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
183
144

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?