Codechef Cook 101 Editorial
Codechef Cook 101 で自分が解いた部分までの解説です (Div2 の4問目、Div1の3問目まで)。
各問題にはテストケース数 の制約があるけど省略しています。
Camp Or Not
概要
競プロキャンプに向けて問題を解く。 問題を解くスケジュールは 日決まっていて、 日目に 問を解く予定である ()。
キャンプの選抜方法の候補は 個あり、各候補には締め切り と 必要問題数 が与えられている。 日目を含むその日までに 問以上解いていれば、キャンプに行くことができる。
スケジュール通りしたときに、各候補日についてキャンプに行けるかどうかを判定せよ。
解法
制約が小さいので愚直にやってもよいし、累積和を計算してもよい。
提出コード : Solution: 25750755 | CodeChef
Yalalovichik Numbers
概要
10進数で桁数が の数 が与えられる (, の各桁は0でない)。 この数を 回左に回した数を とする (例えば のとき、)。
このとき の順で結合した数を で割った余りを求めよ ( なら 123231312 が答え)。
解法
答えは
となる。10のベキの方は簡単に計算できるため が分かれば良い。
まず はそのまま計算できる。 次に については、 の先頭の桁を とすると という関係が成り立つので、 さえ分かれば と順に求めることができる。
今、 を順番に左に回しているので は の 桁目である。 は文字列として与えられているので はすぐに求められる。
提出コード : Solution: 25751450 | CodeChef
Yalalovichik Strings
概要
文字列 のすべての部分文字列(連続)の集合と のすべての部分列(連続とは限らない)の集合が一致するとき、 文字列 は Yalalovichik string であるという。
長さ の文字列 が与えられる ()。 の空でない部分文字列のうち Yalalovichik string であるものの個数を求めよ。
解法
どのような文字列が Yalalovichik string になるかを考える (以降、省略してY文字列と呼ぶ)。
まず1種類の文字が続く場合 (aaaaaa など) は明らかにY文字列になる。
そして文字列が2種類の連からなるとき (aaaabb など) もY文字列になる
(どのように部分列をとっても a*b*
の形になるため)。
逆に文字列が3種類以上の連からなるときはY文字列になることができない。 が と3つ以上の連からできているとする。 このとき部分列として を選ぶと、これは からどのように部分文字列を 選んでも一致させることができないからである。
このことからの部分文字列のうち
- aaa... のように1種類の文字からなる文字列
- a...ab...b のように2種類の連からなる文字列
のどちらかの形をした部分文字列の総数が答えになる。 重複を考慮して数えなければならないが、1 と 2 は独立に考えることができる。
(1) はアルファベット ごとに 中の の最長の長さ をもっておけば、 その総数は になる。
(2) は2種類のアルファベット とそれぞれの長さだけが重要になる。 そのためすべてのアルファベットの対ごとに、 中で取りうるすべての長さの組の集合 を計算する。 例えば aaabb と aabbb の2種類の部分文字列が に現れるとき、 となる。
を をこの順に少なくとも1つずつ使って作れる文字列の個数としよう。 上の例だと になる。
基本的には各 について の和を取ればよいが、これだと 重複を数えてしまうことがある (上の例だと ab, abb, aab, aabb の4種類)。 この問題は2次元平面上に点 がいくつか与えられ、各点ごとに点と原点を隅に持つ長方形を 描いたときの面積の総和を求めることと等価である。 これはそれぞれの点 をx座標でソートして、x座標が小さい方から順に点を見ていくことで計算できる。
異なる は独立に計算できるため、求める総数は である。
計算量はソートの部分が一番重くて である (アルファベットの個数は定数個なので)。
実装は を最初にランレングス符号化しておくと簡単になる (気がする)。
提出コード : Solution: 25753643 | CodeChef
Swag Subsets
概要
長さ の数列 と が与えられる。
集合 の空でない部分集合 について、その swagness を以下のように定める。
このとき をで割った余りを求めよ。
解法
簡単のために はすべて相異なるとする。
まず B を無視した問題 の総和を求めることを考える。 数列 の順序に意味はないのでソートして と仮定してもよい。
このとき となる は 個ある ( を取ればそれ以外は取っても取らなくても良いので)。 同様に となる のとり方は 通りある ( は取らず は取る、それ以外はどちらでもよい)。
これは となるまで同じように考えることができるので、答えは
である。
もとの問題も今の考え方と同じようにする。 まず のペアを をキーでソートして にする。 についてはソートされているとは限らない。
また、 の値だけでソートした列を とする。
となる のとり方は、 を取りそれ以外はどちらでもよいので 通りある。 また をすでに選んでいるので が成り立つ。 それらのうち
で場合分けする。
また を
となる数とする。
ある集合 について(1) が成り立つ条件は よりも右側にある数に対応する添字を取るときである。 を より右にあるものとして、 となる場合を考える。 これは より右にあるものは取らず、 (とすでに選んでいる )を選び、それ以外はどちらでもよい取り方になるので、 の選び方は 通りある。
つまり任意の について となる の取り方は 通りある。 よって (1)の場合の求める数は である。
(2) が起きるのは より右側はすべて取らず、左側はどちらでもよい取り方になるので、 通りある。よって求める数は となる。
以上から となるときの答えは (1), (2) を合わせて
である。
次に となる場合を計算したい。 これは の列から を削除してから、同じ方法で計算することができる。
以上より の計算方法は分かった。あとはこれを高速に計算できるように実装する必要がある。 数列 に対して、上で必要になる操作は
- 与えられた区間 について を求める (上の計算式と少し違うが、全体に を掛けて調整できるためok)
- 要素の削除
の2種類。しかし(2) の要素の削除を考えると面倒なので、 が0 となる部分は無視するように (1) の計算方法を下のように変える。これで(2)の処理も簡単になる。
- 与えられた区間 の のうち、非0 の要素を集めたものを として を求める
- にする。
(1)の計算は次のように言い換えられる。 要素 とし、その上の 演算 を で定める。 このとき(1)の計算は の第一成分と一致する。
この演算はモノイドになっている(単位元は ) のでセグメント木が使える。 この演算は を前計算することで で計算できるので、(1)は で計算することができる。
これを と順番に処理していけば良いので全体の計算量は である。
また、 はすべて相異なるとしていたが、上の計算方法では重複した要素があっても問題なく計算できる。
提出コード : Solution: 25832307 | CodeChef