(APG4b)が開始されました。(APG4b)は終了しました。偽の時の式マクロを使うと変数を使う感覚でプログラムを置換することができるラムダ式を使うと関数の内部で関数を定義できるdo-while文とnext_permutation関数を使うと「順列の全列挙」が簡単に書けるgoto文は多重ループからの脱出に便利3.06.その他の機能このページでは競技プログラミングに役立つことがあり、今まで説明してこなかった細々とした知識について説明します。今回の問題はこのページで説明した内容を使わなくても解けるので、読まずに問題を解いても良いです。EX26.電卓を作ろう3文字コードコンピュータの内部では「文字」を数値として扱っています。ある文字が内部でどのような数値になっているかは、char型の値をint型にキャストすることで見られます。int型をchar型にキャストすることで、数値と対応している文字を見ることもできます。次のプログラムは文字とそれに対応する数値を出力する例です。endl;}実行結果656690ABZ「ある文字に対応する数値」のことを文字コードと呼びます。「全ての文字と数値の対応関係」をまとめて文字コードと呼ぶこともあります。後者の意味で、文字コードには様々な物があります。char型やstring型は通常ASCII文字コード(アスキー文字コード)というものを用いています。ASCII文字コードは基本的に半角英数字と半角記号('0'、'A'、'a'、'!'等)を扱うためのものです。char型やstring型では日本語がうまく扱えないのはそれらがASCIIコードを前提としているためです。ASCII文字コードにおける文字と数値の対応はWikipediaで見ることができます。「大文字は小文字より小さい数値に対応していること」は覚えておくと役に立つことがあります。文字コードを利用したプログラムchar型の値は実質的に数値なので、int型と同じように四則演算や比較ができます。次のプログラムはこれを用いて'A'~'Z'を出力します。i)で「'A'からi文字進めた文字」を計算しています。char型に対して四則演算をした結果はint型になるため、出力する前にchar型にキャストし直す必要があることに注意してください。他にも、次のようにして大文字と小文字を変換することもできます。大文字→小文字この処理はC++で用意されている関数を使って行うこともできます。小文字→大文字の変換は(char)toupper(文字)、大文字→小文字の変換は(char)tolower(文字)で利用できます。次のプログラムは文字コードを比較することにより、大文字と小文字の判定を行っています。'Z'だけで判定ができます。大文字の判定はC++で用意されている関数を使ってisupper(文字)で行うこともできます。同様の便利な関数として小文字の判定を行うislowerや、10進数の数字かどうかをチェックするisdigitなどもあります。今まで出てきた変数のように、関数の中で宣言した変数をローカル変数と呼びます。変数は関数の外で宣言することもできます。関数の外で宣言した変数はグローバル変数と呼びます。グローバル変数の使い方はローカル変数と全く同じです。endl;}実行結果10グローバル変数のスコープグローバル変数のスコープはプログラム全体、つまり「宣言された場所からプログラムの終わりまで」になります。そのため、複数の関数をまたいで使うことができます。endl;}実行結果105グローバル変数名の衝突ローカル変数と同様に、同じ名前のグローバル変数は宣言できません。まれにSTLで定義しているグローバル変数と衝突することもあるので注意してください。const修飾子const修飾子を変数の宣言時につけると、その変数を定数(変えられない値)として扱えるようになります。宣言は次の形式になります。値;値が変えられないこと以外は変数と同じように使うことができます。5;}const修飾子の使い所const修飾子の使い所として、bitsetのビット数を指定する場合があります。bitsetのビット数は定数でなければなりませんが、何度もbitsetの型を書かないといけない場合を考えると、直接数値を書くのは面倒な上に書き間違えの恐れもあります。「const修飾子を付けた変数」を使えば直接数値を書くこと無く、楽かつ安全にbitsetのビット数を指定できます。...}他にも1.13.配列の細かい話で紹介した「Cの配列」やarrayの要素数の指定も定数である必要があるため、「const修飾子を付けた変数」が利用できます。値が変わらないことを保証することで安全にプログラムを書くという目的でconst修飾子を利用することもあります。GCC環境では、ローカル変数であれば「Cの配列」の要素数は変数で指定できます。条件演算子if文の書き換え条件演算子(または三項演算子)を使うとif文を短く書き換えられることがあります。次のプログラムは2つの数値の入力のうち小さい方を出力をif文を用いて実装しています。endl;}これは条件演算子を使うと次のように書き換えられます。endl;}このように、if文で分岐して値を選ぶ処理は条件演算子で短く書くことができます。条件演算子の書き方は次のようになります。条件演算子のネスト条件演算子もif文のようにネストさせることができます。次のプログラムは3つの入力を受け取り、その中で最小の数値を出力しています。endl;}このように条件演算子のネストを書いてしまうと読み辛くなりやすいため、次のように改行とインデントを用いて読みやすくした方が良いでしょう。c;条件が複雑に入り組んでいる場合は条件演算子を使わないほうが読みやすいこともあります。状況に応じて読み書きしやすい方を使いましょう。演算子の優先順位の関係で、coutの内部で条件演算子を利用する場合は()で囲う必要があります。()で囲う}細かく言うと、条件演算子は代入演算子=や複合代入演算子◯=の次に演算子の優先順位が低いです。次の2行のプログラムは同じ意味になります。明示的に()で指定マクロマクロ(defineディレクティブ)は付録4.ループの裏技repマクロで紹介した「repマクロ」を作成するために利用した機能です。マクロを使うと、変数を使う感覚でプログラムを置換することができます。次のプログラムはmy_coutという名前のマクロを定義しています。"hello";}実行結果hello単純なマクロの記法マクロは次のように書きます。半角スペースで区切って定義することに気をつけてください。引数を取るマクロマクロは関数のように引数を受け取ることもできます。次のプログラムはis_not_5という名前のマクロを定義しています。引数を取るマクロは次のように書きます。置き換えるプログラム複数行のマクロマクロの「置き換えるプログラム」が複数行に渡る場合、行末に\を書く必要があります。以下はその定義の例です。endl;repマクロの正体repマクロの定義は次のようになっています。カウンタ変数++)という形式に変換しています。マクロの注意点マクロを使うと短くプログラムを書くことができますが、「単純にプログラムを置換する」という動作の性質上、多くの落とし穴があります。競技プログラミングのような小規模なプログラムではあまり問題になりませんが、大規模な開発では不用意にマクロを定義することは避けられることが多いです。allマクロ競技プログラミングでrepマクロの次に多く使われているマクロがallマクロです。allマクロはsort等の関数呼び出しを簡潔にします。自己責任で利用してください。endl;}ラムダ式ラムダ式を利用すると関数の内部で関数を定義できます。次のプログラムはmain関数の内部で、ラムダ式を用いてmy_min関数を定義しています。基本的なラムダ式の記法は次の通りです。セミコロンが末尾に必要だということに注意してください。};ラムダ式の外の変数の利用[&]と書くことでラムダ式の外の変数を利用できます。次のupdate_max関数はmain関数の内部で定義されているmax_numを利用しています。endl;}実行結果551010この他にもラムダ式にはいくつかの機能があります。気になる人は調べてみてください。ラムダ式による再帰関数ラムダ式で再帰呼び出しのある関数を定義する場合、autoではなくfunctionを型として指定する必要があります。次のプログラムは0~Nの和を求める再帰関数sumをラムダ式で定義しています。再帰呼び出しのあるラムダ式は次のように定義します。返り値の型と引数の型をfunction<>の中に書いたうえ、[&]と書く必要があることに注意して下さい。};ラムダ式の使い道ラムダ式は短い関数をその場で定義したい時に便利です。その例として「sort関数の比較関数の変更」を説明します。配列.end())のように呼び出しますが、三番目の引数に関数を渡して比較方法を変更することができます。次のプログラムはsort関数に自分で定義した比較関数を渡すことで、大きい順にソートさせています。1}となっている}実行結果3名前をつけることを省略してさらに短く書くことも可能です。引数に直接渡す場合はセミコロンが不要になります。今まで説明してこなかったループ構文として、do-while文があります。do-while文は通常のwhile文と異なり、条件式の判定を行うより前に一度だけループ内部の処理を実行します。...」という順番で実行します。次のプログラムは入力で受け取った数を0までカウントダウンして出力します。入力が負の数だった場合は一度だけ出力してプログラムを終了します。0);}入力13実行結果13210入力2-5実行結果2-5この例のように、条件式がはじめから偽でも一度だけ実行することが特徴です。ほとんどの場合はwhile文で十分なのでdo-while文を使うべき場面は基本的にありません。ここでは次で紹介するnext_permutation関数の説明を行うためにdo-while文を紹介しました。next_permutation関数next_permutation関数は「順列の全列挙」を行うための関数です。}という配列に対して、すべての順列を出力しています。順列とはこの例のように、値の集合を順番に並べたもののことを言います。正確にはnext_permutation関数は「区別可能なn個の対象から重複を許してk個の対象を取り出して特定の順番で並べたもの」を全列挙するための関数になります。next_permutation関数の使い方next_permutation関数は次のように使います。事前にsortが必要なことに注意してください。配列変数.end()));「順列の全列挙」は再帰関数で実装することもできますが、next_permutation関数を使ったほうが簡単に実装することができます。next_permutation関数の計算量next_permutation関数を使って順列の全列挙を行った場合の計算量は、配列の長さをNとするとO(N!)になります。Nが小さくても計算量は大きくなるので、使う際は計算量に気をつけましょう。以下はnext_permutation関数を使って解ける問題です。単純な制御構文としてgoto文があります。goto文に到達すると、ラベルを付けた行に移動します。endl;を飛ばしてSKIPラベルの行に実行を移します。AtCoder!goto文の記法goto文は以下のように使います。ラベルの定義ラベルは次のようにラベル名の後に:を書きます。ラベル名:goto文gotoの後にラベル名を指定します。goto文を実行するとラベルの行に実行が移ります。ラベル名;goto文の使い道goto文の使い道として最も便利なのが多重ループからの脱出です。次のプログラムはgoto文を使ってループの外に飛ぶことで、多重ループから簡単に抜けています。1fingoto文の注意点goto文はシンプルな機能ですが、シンプルすぎるためにプログラムが何を意図しているのか分かりにくいことをはじめ、いくつかの落とし穴があります。多重ループからの脱出など一部の状況では使っても良いですが、goto文が必要になるケースはほとんどないので、基本的には使わないほうが良いです。今回の問題はこのページで説明した内容を使わなくても解けるので、読まずに問題を解いても良いです。演習問題リンク先の問題を解いてください。reserved.ページトップ。