-FNS->

競プロでよく使うPythonの構文

最終更新:

forns

- view
メンバー限定 登録/ログイン

競プロの問題を解く流れ


基本は寿司屋です。何を言ってるか分からないという方は、下図と説明をご覧ください。

ほとんどの問題の流れは次のとおりです。

①問題「ご飯とお皿と寿司ネタを渡すので、これらを使って、どんな寿司ネタでも必ずちゃんとお寿司を作れるような機械を作ってください。」

②機械を作る

③実行する(問題で提出すると、いくつかの「ご飯、寿司ネタ、お皿」セットが作った機械に入れられる)。うまくお寿司を作れたらその機械はちゃんとした機械として認定され、合格判定がもらえる!

つまり、きちんとした機械を作成し、競プロで点数をもらうためには、機械で「入力を受け取り」、「出力する」必要があるんです!
競プロでは必須となるその2つのプログラムが必要なわけですね。

それらはほとんどいつも同じものを使うため、まずは実際の問題を見ていく前に、それらについて見ていきましょう!

入力・出力の前に

申し訳ございません。競プロを始める前には、なんと言っても使う言語の基礎を学ぶ必要があるのです。おそらくこのページが一番分かりやすいと思いますので、まずこちらをご覧ください。

出力

前のリンクを見て頭が混乱してしまった方もいるかもしれません。しかし大丈夫です!ここからはしっかり、なるべく簡単にご説明します。
入力より出力の方が簡単なので、まずはこちらから。

1つ目

競プロにおいて、回答を答える方法は1つです。
print(answer) #answerが答えです
本当にこれだけです。簡単です。
answerを出力してね、という意味のPCへの命令です。

+ Pythonでの#の意味についての余談
ちなみに、Pythonのプログラムにおいて#とはコメントアウトを意味します。
print(answer)  #こんにちは!私は犬が大好きです。
残念ながらPythonには、#から改行までの文字を読まないというルールがあります。
つまりこのプログラムでは、PC君にはあなたの犬への情熱は伝わらないのです。

2つ目

本当にprint(〜〜)が基礎ですが、1つ便利な書き方があるのでご紹介します。
時々こんな形式の問題があります。
答え「9」「8」「5」「8」「3」「7」「2」を次のように出力してください。
9 8 5 8 3 7 2
こんな時に、「9 8 5 8 3 7 2」という文字列を作るのはとても面倒です。なぜなら、「9」「8」「5」「8」「3」「7」「2」という答えを半角スペースで繋ぎ合わせるというプログラムが追加で必要になってしまうからです。

そんな時に役に立つのは、リストと*です。
使い方はこうです。

①数字たちをlist(こちらに説明があります)に入れる
list1 = [9, 8, 5, 8, 3, 7, 2]
②list1を出力
print(*list1) # どっちでもいける

2行目に関しては、こんな使い方自分も知りませんでしたが、list名に*をつけてprintすることで、listの中身を半角スペースを開けて最初から順番に出力してくれるらしいんです。
これが本当に便利なので、ぜひ覚えておくと良いです。

3つ目

最後にもう1つ!次のリストを
S = ['a', 'b', 'c', 'd', 'e']
次のように出力したい場合はどうすれば良いでしょうか?
abcde
それは、joinという関数を使えばできます。
print(''.join(list)) # list1の中身がstr(文字列)の場合のみ
joinは、'〜'という文字列で、listの要素をつなげてね、という命令です。
今回は''の中身が何もないので、文字列の間に何も追加することなく、ただただ要素をつなげることになります。よって上記のような結果になるわけですね。

入力

まずはこれ!

入力にはいくつかパターンがあります。
一番基本の形はこちらです。
N = input() #Nは変数名です。なんでもいいよ〜
N = int(input()) #整数にしたいときはinput()の周りにint()を書こう!
#int(S)は、Sを文字列ではなく整数にしてね、という命令です。
こちらは、1行分の入力をNという変数に代入してね、という命令です。
つまり、
N1
N2
N3
という入力があった場合、
N1 = input()
N2 = input()
N3 = input()
または、for文がわかる方は、
N = []
for i in range(3):
    N.append(input())
と書くことで、N = [N1, N2, N3]というリストを作ることも可能なのです。

複数あると?

n m
という入力を受け取るときはどうしたら良いでしょうか?
S = input()
と受け取ると、S = 'n m'となってしまい、nとmという情報をそのまま手に入れることができません。言ってみれば、ご飯の上にお皿が乗った状態で受け取るようなものです。
そんな時にはこんな書き方をします。
N, M = map(int, input().split())
これは、以下のような手順を踏んで、それぞれのn、mを受け取っています。

input()で、'n m'という文字列を受け取る

split()で、' 'があるところで文字を区切ってlistにする [n, m]

intで、nとmを整数にする

mapで、Nに整数n、Mに整数mを代入する(map関数については著者もよく分かっていないので、あまり当てにせず、気になった方は調べることをおすすめします)

listの合わせ技もできます。
N = list(map(int, input().split()))
こうすることで、整数n、mをlist[n、m]にして、Nに代入できます。


実践問題

入力と出力の実践をして見ましょう。

例えばこんな問題があるとします。ちなみにちゃんと読まなくても大丈夫です。
ふーーーん、なるほどね、と思っていただければ大丈夫です。

【問題文】
英小文字からなる長さ N の文字列 S が与えられます。
S の各文字は色 1 、色 2 、… 、色 M の M 色のうちのいずれかで塗られており、 i=1,2,…,N について、S の i 文字目は色 Ci で塗られています。各 i=1,2,…,M について、この順番に下記の操作を行います。S の色 i で塗られた文字からなる部分を、右に 1 つ巡回シフトする。 すなわち、S の 色 i で塗られた文字の位置が先頭のものから順に p1, p2, p3, …, pk 文字目であるとき、
S の p1, p2, p3, …, pk 文字目を、それぞれ、S の pk, p1, p2​, …, pk−1 文字目で同時に置き換える。
上記の操作をすべて行った後の、最終的な S を出力してください。

なお、M 色あるどの色についても、その色で塗られた
S の文字が必ず 1 つ以上存在することが、制約として保証されます。

【制約】
  • 1≤M≤N≤2×105
  • 1≤Ci≤M
  • N,M,Ci はすべて整数
  • S は英小文字からなる長さ N の文字列
  • 任意の整数 1≤i≤M に対して、ある整数 1≤j≤N が存在して Cj=i が成り立つ

【入力】
入力は以下の形式で標準入力から与えられる。
N M
S
C1 C2 … CN

【出力】
cszapqbr

とても難しくて何を言っているかよく分からない、と思った方も多いと思います。

簡単に説明すると、以下の通りです。

同じ色を順番に右に回してできた文字列は何か、という問題です。
制約によると、
  • 色と文字列Sの数の条件は1以上2×105以下
などなどいくつかありますが、今回は省略します。

入力

入力は以下の形式で標準入力から与えられる。
N M
S
C1 C2 … CN

◎具体例
8 3
apzbqrcs
1 2 3 1 2 2 1 2

この場合、入力はどのようになるでしょうか?


①1行目
8 3
まず上記を受け取る必要があります。複数あって、整数で受け取りたいため、
N, M = map(int, input().split())
になりますね。

②2行目
apzbqrcs
次に上記を受け取ります。1つの文字列として受け取る場合は
S = input()
で良いですし、1文字ずつのリストで受け取りたい場合は
S = input()
Slist = []
for i in range(len(Slist)): #len(list名)は、listの要素の数を教えてー、という命令
    Slist.append(S[i]) # 文字列Sを1文字ずつSlistに要素として入れていく
で良いわけです。この問題では、この後文字の位置を変えたりする都合上、文字を1つ1つlistとして入れていく、2つ目の方法が良さそうですね。

+ このプログラムの注意事項
①iについて
ここでiは、繰り返し処理をするたびに変わる変数となります。
ここでは、繰り返し1回目から順番に、0 〜(Slistの要素-1)に変わっていきます。
0から順に変わっていくことに注意しましょう。

②listや文字列の指定について
listや文字列Sの中の「この部分」だけを取り出したいときはどうすれば良いでしょうか?
そんなときは、
list[0] # listの1つ目
S[1] # 文字列の2文字目
このようにすればOKです。こちらも①と同様、0から順番に数えられることに注意しましょう。

③3行目
最後にこちらです。
1 2 3 1 2 2 1 2
こちらは整数を1つ1つlistとして受け取りたいところですね。なので、以下のようなプログラムになります。
C = list(map(int, input().split()))

【出力】

出力はこちらです。
cszapqbr
この問題の性質上、文字列を交換した後のlist1['c', 's', 'z', 'a', 'p', 'q', 'b', 'r',]が存在すると考えます。
この場合は、前の出力のところで書いた、3番目の方法でいきます。
print(''.join(list1))

【プログラム全体】

これで入力、出力のプログラムが書けたわけですね。
S = input()
Slist = []
for i in range(len(Slist)):
    Slist.append(S[i])

# Sを操作するプログラム。答えをlist1に入れる

print(''.join(list1))

最後に

こんな感じが競プロの基礎です。ただ、これは本当に基本中の基本で、競プロで問われるのは入力をいかにして出力の形に変えるかです。この入力と出力の形を覚えて、すらすら書けるようにしていきましょう!
ウィキ募集バナー