# Atcoderで始める競技プログラミング入門 C/C++編 [本体](https://hackmd.io/s/r1XMWfBnE) ## はじめてのAtcoder(入出力) [問題](https://atcoder.jp/contests/practice/tasks/practice_1) 入出力は言語によっては最大の難所になっている事もある、なので確認も兼ねて基本的なやり方を紹介する。 解答例: ```cpp= #include <iostream> using namespace std; int main() { int a; int b, c; string s; cin >> a; cin >> b >> c; cin >> s; cout << (a+b+c) << " " << s << endl; return 0; } ``` ### 解説 #### おまじない1 ```#include <iostream>``` ```#include <iostream>```は入出力を行う機能を使えるようにする為のものです、他にも色々な機能があるので後々紹介します。 ##### 最強の呪文 ```#include <bits/stdc++.h>``` (gcc限定) gccでは```#include <bits/stdc++.h>```で標準的な機能を大体読み込むことができます。 ただし、その分コンパイルに時間がかかったりするので一長一短です。 また、提出する際に向こうの実行環境がgccである事の確認も忘れないよう注意。 clangの場合、手元には自分でファイルを置いて提出をgccにするなど、ただし環境が違うと同じコードでもコンパイルが通らなかったりするから注意。 #### おまじない2 ```using namespace std;``` ```using namespace std;```とは本来、読み込んだ機能を使うには```std::cin```のように、機能の前に```std::```のようなものを指定しないといけないのですが、それを省略できるようにするものです。 ```std::```は本来、機能の名前が被らないようにするための物なので*競技プログラミング以外では使わないでください*。 ##### 普段usingを使いたい時 実はusingは以下のように色々な書き方が出来ます、競技プログラミング以外で使いたい時は用途に合わせて使い分けてください。 ```cpp= #include <iostream> int main() { for(int i=1;i<=10;++i) { // スコープ({}の事)の中だけで利用 using namespace std; cout << i << endl; } // cout << 100 << endl; // ここでは省略出来ない std::cout << 100 << std::endl; } ``` ```cpp= #include <iostream> using std::cin; // 省略したいものだけ宣言 using std::cout; int main() { int a; cin >> a; cout << a << std::endl; // endlのstd::は宣言してないので省略できない return 0; } ``` #### 変数宣言と入力について C++では入力を受け取るために先に変数を用意(宣言)します。 入出力の種類に合わせて変数の型を変える必要があるので次の表を参照してください。 |入力の種類|変数の型| |:--:|:--:| |整数(~10^9くらい)|int| |整数(~10^18くらい)|long long| |文字|char| |文字列|char[], string| |小数|(float, )double, long double| C++自体には他にもbool型などがあるが、入力で使うのは基本的にこの辺。 cinはscanfと違って入力を型を元に勝手に解釈してくれるから整数も文字列も同じ```cin >> x;```で受け取る事ができる。また、```cin >> x >> y;```のように繋げて受け取る事もできる。なので、上のコードの入力は次のようにまとめる事もできる。(入力の区切りは半角スペースor改行で行われる) ```cpp= #include <iostream> using namespace std; int main() { int a, b, c; string s; cin >> a >> b >> c >> s; cout << (a+b+c) << " " << s << endl; return 0; } ``` 問題によっては半角スペース区切りの数列の形をした入力などがあるが、その時は配列などを用意してforループで受け取ると良い。 以下、注意点などを上げておく。 - 整数/小数について - 負の値を取らない時はunsignedをつけると表せる範囲が倍になる(があまり使うことはない)。 - long longはintより大きくて上位互換のように感じるが、その分データが大きいので計算がintに比べて遅かったり(要検証)、メモリの使いすぎ(配列で用意した時など)で不正解扱いになったりするので注意。 - 本当はintやlong longの大きさは処理系依存(下限とint<=long longは決まってる)だが、基本的にintは32bit, long longは64bitだと思っておけばよい(小数も同様) - 大きさを気にする時はint64_tなどを使うとよい - 文字列について - stringは本来は```#include <string>```をしないとならないが、```#include <iostream>```をした際に、依存関係により読み込まれているだけなので、```#include <cstdio>```(C言語の入出力)を使う際などには注意。 - そもそもscanfでstringを読み込むことは出来ないので注意。 - char\[\](charの配列)を用いる時は文字列の長さ(の上限)を指定しなければならない - 実は、```char s[] = {};``` のように初期化してあれば大丈夫(要検証) - 基本的に入力は空白で区切られてしまうので、空白込みで一行分の文字列が欲しい時は```getline(cin, s)```を使う。(sはstring) ##### 型の省略 long longの最大の難点はタイプ数が多さ型名に空白は入っていて分かりづらい事だと思います。 また後述する動的配列(vector)などを使おうと思うともっとタイプ数が多いものや紛らわしいのもが出てきます。 そこで既に出てきたusingを使うことで型名を短くできます。 ```cpp= #include <iostream> using namespace std; using ll = long long; // long long を ll に int main() { ll a; // long long 型になる return 0; } ``` ##### AOJでの入力 AOJは入力が独特な問題あり、闇テクニックがあるので紹介にだけしておく。 ++入力の終わりがEOF(End of File)の場合++ [問題](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0005) ```cpp= #include <iostream> using namespace std; using ll = long long; inline ll gcd(const ll &a, const ll &b) { return b==0 ? a : gcd(b, a%b); } inline ll lcm(const ll &a, const ll &b) { return a / gcd(a, b) * b; } int main() { long long a, b; while(cin >> a >> b) { cout << gcd(a, b) << ' ' << lcm(a, b) << endl; // if(cin.eof()) break; // これでも判別できる } return 0; } ``` ++入力の終わりが0(単数)の場合++ [問題](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_3_B) ```cpp= #include <iostream> using namespace std; int main() { int i = 1, x; while(cin>>x, x) { // ,の右側だけ評価に利用される、0はfalseに解釈される cout << "Case " << i << ": " << x << endl; ++i; } return 0; } ``` for文でも同様のことができる。 この問題の場合、そちらの方が簡潔に書ける。(スコープ的にもこちらの方がよい) ```cpp= #include <iostream> using namespace std; int main() { for(int i=1, x; cin>>x, x; ++i) { cout << "Case " << i << ": " << x << endl; } return 0; } ``` ++入力の終わりが0(複数)の場合++ [問題](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_3_C) ```cpp= #include <iostream> using namespace std; int main() { int x, y; while(cin>>x>>y, x|y) { // |なbitごとにorを取るのでx==y==0の時だけ0、つまりfalseになる if(x < y) cout << x << ' ' << y << endl; else cout << y << ' ' << x << endl; } return 0; } ``` #### 出力について 出力にはcoutを使いますcinと同様に繋げられますが、シフトの向きが逆(```<<```)なので気をつけてください。(値を渡す先を向いてるイメージ) 実は```<<```はシフト演算子(のオーバーロード)なので演算に優先度があります、なので計算を挟む際には```<< (a+b+c) <<```のように括弧をつけることをオススメします。 また、改行はendlで出来ます。(```'\n'```でもok) ##### 小数の桁数指定について coutで桁数を指定するのはめんどくさいです。(直球) ここの[リンク](https://marycore.jp/prog/cpp/stream-format-float/)などを参照するか、大人しくprintfを使いましょう。 ただし、Atcoderでは(幾何問題があまり出ない傾向にあるので)小数の出力を求められるケースは少ないので、coutを使っていても大丈夫です。 ##### cin, coutの高速化 cin, coutは高機能な分、scanf, printfに比べて倍くらい遅いです。 競技プログラミングは入力よりもその後の処理に時間がかかる事が多いので入出力で問題になる事は多くないですが一応速いことに越した事はないので紹介しておきます。 ```cpp= #include <iostream> using namespace std; int main() { cin.tie(0); // cinとcoutの同期を切る。cout.tie(0)もある。 ios::sync_with_stdio(false); // cin, coutとscanf, printfの同期を切る return 0; } ``` ```ios::sync_with_stdio(false);```に関しては、特にcoutとprintfの同期を切っているので、二つを混ぜて出力する事は避けましょう。 #### コメントについて コメントは人間が「プログラムがどういう動作をしているか」等のメモ書きをプログラム中に残しておくための機能です。 プログラムとしての意味はないので、書いても動作に影響はありません。(コピペ) 詳しくはコピー元の[APG4b](https://atcoder.jp/contests/APG4b/tasks/APG4b_b)に書いてあるのでそちらを参照。 #### エラーについて プログラムを提出した際、うまくいくとAC(Accept)と表示されますが、うまくいかないとWA(wrong answer)などが表示されます。 これも詳しいエラーの種類などは[APG4b](https://atcoder.jp/contests/APG4b/tasks/APG4b_c)に書いてあるのでそちらを参照。 以上でC++で競技プログラミングを始める上での基本は押さえました。 次からは競技プログラミングをする上でのテクニックなどを紹介していきます。