AtCoder Beginner Contest 250 メモ(A-D)
今回の結果
2AC
C問題があと5分あれば解けた。
A問題やB問題は求めるコーディングスキルは変わってないが、
与えられた問題からどのようにコードに落とし込むかを考えさせているなー、と問題文を読んでて思った。
A - Adjacent Squares
問題
Difficulty:25
問題文
縦
このとき、マス
ただし、ある 2 つのマス
制約
- 入力は全て整数
1≤R≤H≤10 1≤C≤W≤10
入力
入力は以下の形式で標準入力から与えられる。
H W
R C
出力
答えを整数として出力せよ。
参加中に考えたこと
問題文の但し書きにちょっとびっくりした。
これって要は
入出力例にある図を見れば分かるんだけど、上下左右それぞれに1つずらして
つまり、
というわけで、判定のところは以下の4つの分岐を並べて解いた。
int ans = 0;
if(R > 1) ++ans;
if(R < H) ++ans;
if(C > 1) ++ans;
if(C < W) ++ans;
考察・感想
公式と同じ解き方でしたね。
B - Enlarged Checker Board
問題
Difficulty:109
問題文
縦
- 各タイルは白いタイルまたは黒いタイルである。
- 白いタイルのすべてのマスは白で塗られ、黒いタイルのすべてのマスは黒で塗られている。
- タイル
は白いタイルである。(1,1) - 辺で隣接する
つのタイルは異なる色のタイルである。ただし、タイル2 とタイル(a,b) が辺で隣接するとは、(c,d) (∣a−c∣+∣b−d∣=1 を∣x∣ の絶対値とする)であることを言う。x
マス目
制約
1≤N,A,B≤10 - 入力は全て整数
入力
入力は以下の形式で標準入力から与えられる。
N A B
出力
次の条件をみたす
を改行区切りで出力せよ。
-
はそれぞれ長さS_1 ,\dots,S_{A×N} の(B×N) .
または#
からなる文字列である。 - 各
に対し、マス目i,j (1≤i≤A×N,1≤j≤B×N) の上からX 行目かつ左からi 列目のマスが白で塗られているならばj のS i 文字目はj .
であり、黒く塗られているならば#
である。
入出力例
入力例1
4 3 2
出力例1
..##..##
..##..##
..##..##
##..##..
##..##..
##..##..
..##..##
..##..##
..##..##
##..##..
##..##..
##..##..
参加中に考えたこと
A問題に出てきた隣接の定義がまた出てきて、1つのコンテスト内でそういうのはなかった気がする。
問題文の3つ目の箇条書きから、タイル
難しく考えすぎて時間を無駄にしてしまった。
ただ出力例を見るとその行列になっているので、外側の二重ループはこの2つを終了条件にするでよさそう。
入力例1を見ながらここを考える。
縦を見ると、A=3、N=4なので行数は12。
3つおきに.
と#
が変わっているので、Aでの剰余の偶奇で判定できる。
横についても同様のことができる。
で、縦と横を組み合わせるにはどうするかだけど、これは .
、1なら#
とすればチェック柄が作れた。
ループと
rep(i, A*N){
rep(j, B*N){
int ax = i / A % 2;
int bx = j / B % 2;
if(ax == 1 && bx == 0 || ax == 0 && bx == 1){
cout << '#';
} else {
cout << '.';
}
}
cout << endl;
}
考察・感想
公式解説には実装例が2つあるけど、実装例2のほうで解いた。
公式の実装例2のように二重ループの中の判定部分は1行でも書けますね。
C - Adjacent Swaps
問題
Difficulty:517
灰色よりの茶色レベル問題なのでこれは解きたかった。。
問題文
高橋君は
- 整数
が書かれているボールをその右隣のボールと入れ替える。ただし、整数x_i が書かれているボールが元々右端にあった場合、代わりに左隣のボールと入れ替える。x_i
操作後において左から
制約
2≤N≤2×10^5 1≤Q≤2×10^5 1≤x_i ≤N - 入力は全て整数
入力
入力は以下の形式で標準入力から与えられる。
N Q
x
1
.
.
x
Q
出力
入出力例
入力例1
5 5
1
2
3
4
5
出力例1
1 2 3 5 4
参加中に考えたこと
まずは計算量を考えるところから。
配列を使って問題分の通りに順次処理をすると、
- 配列の中から
を探すのにXi O(N) - swapの計算量は
で、Q回操作するのでO(1) O(Q) - この2つの積になるので、
O(NQ) \fallingdotseq 10^{10}
で、計算量が足りない。
探索を二分探索にすれば、
配列とは別に、数値がどこにあるかのハッシュを持たせたらどうか?
そうすれば探索の部分が
入力例1を使って、配列を
(
i | ||||||
---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | |
1 | 1 | 2 | 1 | 3 | 4 | 5 |
2 | 2 | 1 | 2 | 3 | 4 | 5 |
3 | 3 | 1 | 2 | 4 | 3 | 5 |
4 | 4 | 1 | 2 | 3 | 4 | 5 |
5 | 5 | 1 | 2 | 3 | 5 | 4 |
i | |||||
---|---|---|---|---|---|
0 | 0 | 1 | 2 | 3 | 4 |
1 | 1 | 0 | 2 | 3 | 4 |
2 | 0 | 1 | 2 | 3 | 4 |
3 | 0 | 1 | 3 | 2 | 4 |
4 | 0 | 1 | 2 | 3 | 4 |
5 | 0 | 1 | 2 | 4 | 3 |
これを見ながら、この動きをするようなコードを書く。
処理を順番に書くと以下のようになる。
- コマンド
を受け取るx_i -
の配列上の位置をマップから探す。これをx_i とするmi -
(a[mi+1] が配列の最右の場合はXi )の値を取得。これをa[mi-1] とするai2 - マップから
の値の位置を取得する。これをai2 とするmi2 -
とa[mi] (a[mi+1] が配列の最右の場合はXi )をswapするa[mi-1] -
←m[x_i] mi2 -
←m[ai2] mi
方針が決まってコードを書いていたが、バグから抜け出せずタイムアップ。
考察・感想
あと5分あれば解けてた。
けど、この方法が効率が悪い気がするのでもっといい解法がありそうと思って公式解説を見たら、同じ解き方だった。
ただ公式の実装例のほうが使ってる変数が1個多いが、こっちのほうが可読性は高そう。
変数が多くなると代入先を間違えやすくなるので、実は適した関数やライブラリがあるのかと思ったが、これくらいはできなきゃいかんってことですね。
あと値を管理するのはマップじゃなくて配列でもよかった。
D - 250-like Number
問題
Difficulty:797
問題文
以下の条件を満たす整数
-
が素数k を使ってp<q と表される。k=p×q^3
制約
-
はN 以上1 以下の整数10^{18}
入力
入力は以下の形式で標準入力から与えられる。
N
出力
答えを整数として出力せよ。
入出力例
入力例 1
250
出力例 1
2
入力例 2
1
出力例 2
0
入力例 3
123456789012345
出力例 3
226863
参加中に考えたこと
問題は読んだけど素数判定に使う部品を持ってなかったし、解法を探すのにも時間がかかりそうだったので解くのはあきらめた。。
考察
解説を見る前にもう一度考え直したけどACさせるまでは結構難しかった。
与えられた条件から、
整数に関する部品をまだ持ってないので、素数を列挙するプログラム(エラストテネスの篩)を作ってみて確認すると
なお、
この数に対して全探索をすると
どうしても不安なら二分探索で境界を探しても良い。
最大の値(
C++で解くにあたってはもう1つ考慮が必要な点があって、
そこの工夫までしないとこの問題はACできない。
ここは解説を見て確認した。
解決策としては2通りある。
-
でpを計算して、素数列から条件を満たす最大の値を探すp = min(q-1,\dfrac{n}{q^3})
p = n / (q * q * q)
と書いた場合、q
がint型だとオーバーフローするので注意。
p = n / q / q / q
と書くほうが無難。 -
がlong long型に収まるかを予めdouble型で計算して見積もるp×q^3
Discussion