More Related Content
More from AtCoder Inc. (20)
Square869120 contest #2
- 2. 問題概要
• I, Oからなる文字列 S が与えられる。
• 文字列 S の部分列のうち, 「IOIOI, IOIOIOIOIOIOIOIのような文字列」
の最大の長さを求めなさい。
• 1 ≦ |S| ≦ 10,000
- 4. 部分点解法
• S が T の部分列であるか判定する
1. ptr = 1 とする
2. Tの1文字目から|T|文字目まで:
3. S の ptr 文字目が今指しているTの文字と等しければ ptr を1加算する
4. ptr=|S|であれば部分列である
• その方法を使って, で判定できる
• 全体の計算量は
- 6. 満点解法
• 実は, I, IOI, IOIOI, IOIOIOI,...と調べていく必要はない
• IOIOIOIOI,...IOIOIOIOI のような長さ |S| 以上の文字列 T を用意し, 4ページ
目の部分列であるか判定するアルゴリズムの最終的な ptr を利用することがで
きる
• ptr が 1 ⇒ 列車が編成できない
• ptr が偶数 ⇒ 長さ ptr-1 の列車が編成できる
• ptr が奇数 ⇒ 長さ ptr-2 の列車が編成できる
• 全体の計算量は なのでAcceptedします
- 7. 結果 / Result
• IOI に行っている人やIOI代表選手を決める選考会に参加している人な
らば簡単に解けると思います
• A問題の解説を書いた人は上の条件に該当しないので解くのに10分くら
いかかりました
• IOI列車に乗ってIOIに行きたいけどあと3000問は解かなければあまり現
実的ではないと思いました
- 23. 満点解法2
• 例えば、a={3,4,6},n=20,q=3のとき、Queueは次のように変化します。
• {(1,3)}⇒
• {(6,2),(1,2)}⇒
• {(24,1),(6,1),(4,1),(1,1)}⇒
• {(18,0),(6,0),(12,0),(4,0),(3,0),(1,0)}となります。
• よって、最終的に残っているのは5通りとなります。枝刈りをしているので、数の
重なりはないです。⇒答えはループから抜けたときのQueueのサイズとなります。
• グレーの部分は枝刈りされたものを示しています。
- 30. 例
• 例えば、n=1355,D=50のとき、
• {1,3,5,5}:1+3+5+5=13
• {13,5,5}:13+5+5=23
• {1,35,5}:1+35+5=41
• の3通りの分け方が存在する。
• 答えは、1,000,000,007で割った余りで求めなければならない。
- 50. 例
• ちなみに、 約数が最大となる整数は、 以下のように続きます。(高度合成数)
整数 約数個数 整数 約数個数 整数 約数個数
1 1 48 10 840 32
2 2 60 12 1260 36
4 3 120 16 1680 40
6 4 180 18 2520 48
12 6 240 20 5040 60
24 8 360 24 7560 64
36 9 720 30 10080 72
- 55. 考察1
素因数の 個数を {2,3,5,7} で表した ものです 。(n=30のとき)
{0,0,0,0}=1⇒ {1,0,0,0}=2 ⇒ {2,0,0,0}=4⇒ {3,0,0,0}=8 ⇒ {4,0,0,0}=16⇒ (これ以降は矢
印は省略)
{5,0,0,0}=32 {4,0,0,0}=16 {4,1,0,0}=48 {4,0,0,0}=16 {4,0,1,0}=80 {4,0,0,0}=16
{4,0,0,1}=112 {4,0,0,0}=16 {3,0,0,0}=8 {3,1,0,0}=24 {3,2,0,0}=72 {3,1,0,0}=24
{3,1,1,0}=120 {3,1,0,0}=24 {3,1,0,1}=168 {3,1,0,0}=24 {3,0,0,0}=8 {3,0,1,0}=40
{3,0,0,0}=8 {3,0,0,1}=56 {3,0,0,0}=8 {2,0,0,0}=4 {2,1,0,0}=12 {2,2,0,0}=36
のように 続きます。
- 60. 小課題2(42点)
• 状態遷移は下のようになります。
状態遷移 {2,3,5}= (数,約数) ⇒は省略 します。 n=30
{0,0,0}=(1,1) {1,0,0}=(2,2) {2,0,0}=(4,3) {3,0,0}=(8,4) {4,0,0}=(16,5) {5,0,0}=(32,6)
{4,0,0}=(16,6) {4,1,0}=(48,10) {4,0,0}=(16,6) {3,0,0}=(8,4) {3,1,0}=(24,8) {3,2,0}=(72,12)
{3,1,0}=(24,8) {3,1,1}=(120,16) {3,1,0}=(24,8) {3,0,0}=(8,4) {2,0,0}=(4,3) {2,1,0}=(12,6)
{2,2,0}=(36,9) {2,1,0}=(12,6) {2,1,1}=(60,12) {2,1,0}=(12,6) {2,0,0}=(4,3) {1,0,0}=(2,2)
{1,1,0}=(6,4) {1,2,0}=(18,6) {1,3,0}=(54,8) {1,2,0}=(18,6) {1,2,1}=(90,12) {1,2,0}=(18,6)
{1,1,0}=(6,4) {1,1,1}=(30,8) {1,1,2}=(150,12) {1,1,1}=(30,8) {1,1,0}=(6,4) {1,0,0}=(2,2)
- 65. 満点解法
• 以下のようになります。
{0,0,0}=(1,1) {1,0,0}=(2,2) {2,0,0}=(4,3) {3,0,0}=(8,4) {4,0,0}=(16,5) {5,0,0}=(32,6)
{4,0,0}=(16,5) {3,0,0}=(8,4) {3,1,0}=(24,8) {3,2,0}=(72,12) {3,1,0}=(24,8) {3,0,0}=(8,4)
{2,0,0}=(4,3) {2,1,0}=(12,6) {2,2,0}=(36,9) {2,1,0}=(12,6) {2,0,0}=(4,3) {1,0,0}=(2,2)
{1,1,0}=(6,4) {1,1,1}=(30,8) {1,1,0}=(6,4) {1,0,0}=(2,2) {0,0,0}=(1,1)
これだけです。 緑字は2回戻り の途中を表し ます。
- 67. 参考問題
• JOI 2009-10予選6 「方向音痴のトナカイ」
• AOJ 0190 「11パズル」
• AOJ ALDS1_13_C 「15パズル」
• AOJ 1128 「square carpets」
- 71. 問題概要
• 文字列 S が与えられる。 S の部分文字列の合計の文字数を求めなさい。
ただし, 重複するものは 1 通りだけをカウントする。
• 制約
• 1 ≦ |S| ≦ 100,000
- 72. 問題概要
• S = "abc" のとき
• "a", "b", "c", "ab", "bc", "abc" の 6 個がある。合計は 10文字であ
る。 よって, 答えは 10となる。
• S = "aaqqz" のとき
• "a", "q", "z", "aa", "aq", "qq", "qz", "aaq", "aqq", "qqz", "aaqq",
"aqqz", "aaqqz" の 13個があり, 合計で32文字である。
- 73. 部分点解法 (15点)
• 部分文字列を全部探索し, 重複しているものを 1 回しかカウントしない。
• 部分文字列は合計で O(|S|^3) 文字あるので, これをソートすると全体の
計算量は O(|S|^3 log |S|) かかる。
• こんなに簡単に 12点が取れます。
- 74. 部分点解法 (50点)
• 部分文字列は合計で O(|S|^2) 個しかないので, 文字列を数値に変換す
ればソートに O(|S|^2 log|S|) しかかからない。
• そのようなアルゴリズムをハッシュという。(確率的だが, 99.9%くらい正確と
思っといたほうがいい)
• 長さ k の文字列の場合, の v
の値をハッシュ値とする。unsigned long long型で mod 2^64 を取るのが一
般的。
• 全体の計算量は O(|S|^ 3)
- 75. 部分点解法 (50点)
• Rolling-Hash という方法で S の部分文字列のうち長さ N のもののハッ
シュ値を O(|S|) で求めることができる。
• 分からない方は蟻本やインターネットのページを参考にしてください。
• 全体の計算量は O(|S|^2 log |S|)
- 76. Suffix Array, LCPについて
• Suffix Arrayとは?
• Suffix Arrayとは, 文字列 S の接尾辞をソートしたものである。接尾辞配
列 A[i] は (Sの文字数) - (ソートした時の i 番目の接尾辞の文字数) で
ある。
• 詳しくは蟻本やインターネットを参照。
• これは で求められる。
- 77. Suffix Array, LCPとは?
• たとえば, S = "E869120" のとき,
• 接尾辞配列は右のようになる。
• それを使って, LCPというものを
• O(|S|) で求められるようになる。
• LCPについては次ページで。
i Suffix A[i]
0 (空文字列) 7
1 0 6
2 120 4
3 20 5
4 69120 2
5 869120 1
6 9120 3
7 E869120 0
- 78. Suffix Array, LCPとは?
• Suffixをソートした時の i 番目の文字列をSuffix[i] とする。
• LCP[i] = (Suffix[i-1] と Suffix[i] の最初の何文字が同じか)
• LCPについても蟻本やインターネットに載っているので参考にしてくださ
い。
- 79. 満点解法
• S = "AAQQZ" のとき
i Suffix LCP 重複している文字列 重複していない文字列
1 AAQQZ 0 0個 A,AA, AAQ, AAQQ, AAQQZ
2 AQQZ 1 1個 (A) AQ, AQQ, AQQZ
3 QQZ 0 0個 Q, QQ, QQZ
4 QZ 1 1個 (Q) QZ
5 Z 0 0個 Z
- 80. 満点解法
• S = "AAQQZ" のとき
• 同じになっている!
i Suffix LCP 重複している文字列 重複していない文字列
1 AAQQZ 0 0個 A,AA, AAQ, AAQQ, AAQQZ
2 AQQZ 1 1個 (A) AQ, AQQ, AQQZ
3 QQZ 0 0個 Q, QQ, QQZ
4 QZ 1 1個 (Q) QZ
5 Z 0 0個 Z
- 84. 問題概要
• 長さ a の数列 が に初期化されて
いる。
• 次の操作を c 回行う。
• とする。
• 最終的な の値を mod 1,000,000,007 で求めなさい。
- 85. 問題概要
• 制約
• 1 ≦ a ≦ 100,000
• 1 ≦ b ≦ 1,000,000,000
• 1 ≦ c ≦ 1,000,000,000
- 86. 問題概要
• の時
• よって, 求める答えは58となります。
• 58って, 素晴らしい数ですね。 (rng_58, sky58のようなプロも使っている)
d[0] d[1] d[2] d[3]
最初 1 3 9 27
1回目終了後 1 4 13 40
2回目終了後 1 5 18 58
- 89. 部分点解法(12点) の補足
• DP(Dynamic Programming ) でも解けます
• JOI2006-2007 予選 6問目 「通学経路」 のように DPしていくとできます
• 漸化式は dp[i][j] = dp[i-1][j]+dp[i][j-1] のような感じですね
• この方法でも12点は取れます。
- 90. 考察1
• でも, この問題には JOIの 「通学経路」 のように障害物はありません
• AtCoder Beginner Contest 034 C問題 「経路」 のような場合です
• 「経路」 という問題は, 組み合わせ (nCr) を用いた解法で101点取れます
• そこで, H×W の経路の総数について考えてみましょう
- 92. 考察1
• 次に, を O(n) で求める方法を紹介します。
• フェルマーの小定理を用いて ということが分
かります。その解を 「a の逆元 (mod inverse)」 といいます。
• なので, n! を O(n) で求めて逆元をO(log n) で求めれば結
果として計算量は O(n) となります。
- 93. 考察1
• この問題にも nCr を使うことができます。
• 9 という数字について考えると, 1×1の場合と同じ2通りの経路があり, 最終的な
答えに9×2=18 を足していることが分かります。
d[0] d[1] d[2] d[3]
最初 1 3 9 27
1回目終了後 1 4 13 40
2回目終了後 1 5 18 58
- 94. 部分点解法(60点)
• 最初に説明した例の場合, 答えは であり, 58
となります。
• しかし, そのままでは nCr を求めるのにO(n) かかってしまいます。
• k! を 1 から n までメモ化することによってO(log n) で済みます。
• よって, 全体的な計算量は mod p のとき 約 O(c + a log p) となります。
小課題2には通ります。
- 95. 満点解法
• n が大きい場合の nCr をどのように求めるか?
• を使えばO(r) で求められます
• では, どのようにして を求めるのか?
• 上の方法を利用すれば で求められる。
• もっと高速化する方法はないか?
- 97. 満点解法
• それを順番に求めていくと, O(a log p) ですべて求められます。
• よって, O(a log p) でこの問題を解くことができます。
• この問題は少し数学的な知識が必要かもしれませんが, 蟻本に載ってい
る程度なので解けなかった人はマスターしましょう。
- 98. nCr を利用する問題
• 以下, 私がお勧めする nCr を用いる問題です。
• ProjectEuler 015「Lattice Paths」
• AtCoder Beginner Contest 034 C問題 「経路」
• AtCoder Beginner Contest 022 D問題 「多重ループ」
• AOJ 2335 「10歳の動的計画」
• AOJ 2445「Minimum Cost Path」
- 112. 小課題2(64点)
• 考察1のようにやればよい
• ⇒{a,b}を結ぶ道は条件を満たすか(交点がないか)を求めるクエリとする
• {a,b}=0のとき結べない、1のとき結べるとする
• ⇒{1,2},{1,3},{1,4},{1,5}…{1,n},{2,3},…{2,n},{3,4}…というように、全て
の辺を順に調べる
• この段階で{a,b}=0のときこの道は結ばない、{a,b}=1のとき結ぶ
• このような方法でやると、無駄な四角形の部分がなくなる
- 126. はじめに
• square869120Contest #2 にご参加いただきありがとうございます。
• 私は解法を考えるのに 2 日かかりましたが, G問題はもっとかかりました。
• 問題を考えてから思ったんだけど, JAGAsia 2012 にも Counting 1's とい
う問題があったが, 全然違う問題である。そもそもJAGの方のCounting
1'sは難易度が高すぎます。
- 128. 問題概要
• 長さ N のビット列 a[0], a[1], a[2],...a[N-1] があり, 0 で初期化されている。クエ
リが Q 個与えられ, 次の 2 つの処理のどちらかを行う。
• Query 1: 区間 [l, r) のビットをすべて反転させる
• Query 2: 区間 [l, r) のビットが 1 であるものの個数を数える
• 制約
• 1≦N≦100,000
• 1≦Q≦100,000
- 129. 問題概要
• N=8 , Q=4 のとき (入力例1)
i 0 1 2 3 4 5 6 7
a[i] 0 0 0 0 0 0 0 0
- 130. 問題概要
• N=8 , Q=4 のとき (入力例1)
• Query 1: 区間 [3, 7) のビットを反転させる
i 0 1 2 3 4 5 6 7
a[i] 0 0 0 1 1 1 1 0
- 131. 問題概要
• N=8 , Q=4 のとき (入力例1)
• Query 2: 区間 [2, 5) のビットが1のものの個数を求める ⇒ 2
i 0 1 2 3 4 5 6 7
a[i] 0 0 0 1 1 1 1 0
- 132. 問題概要
• N=8 , Q=4 のとき (入力例1)
• Query 1: 区間 [2, 4) のビットを反転させる
i 0 1 2 3 4 5 6 7
a[i] 0 0 1 0 1 1 1 0
- 133. 問題概要
• N=8 , Q=4 のとき (入力例1)
• Query 2: 区間 [1, 6) のビットが1のものの個数を求める ⇒3
1 0 1 2 3 4 5 6 7
a[i] 0 0 1 0 1 1 1 0
- 135. 部分点解法 (16点)
• 制約
• 1≦N≦100,000
• 1≦Q≦100,000
• Query 2 は 1,000 個以内
• そのままでは Query 1 にO(N), Query2 にO(N) かかっているので間に
合わない
• Query1 の実行速度を速くするためにはどのような方法を使えばよいか?
- 137. 部分点解法 (16点)
• 「いもす法」 とは?
• Query 1: 区間 [l, r) に対してa[i] += x とする
• Query 2: a[0], a[1], ... a[n-1 ] の値を求める
• Query 1 を O(1 ) で, Query2 を O(n) ですることができる。
- 138. 部分点解法 (16点)
• Query 1: s[l] += x, s[r] -= x とする
• Query 2: a[i] = a[i-1] + s[i] である
• そのように, 累積和を応用するだけでそのようなクエリ処理ができる。
• ⇒Query 1 に O(1),Query 2 に O(N) かかる
• ⇒小課題 2 には通る
- 139. 部分点解法 (52点)
• 52 点をとれる解法が思いつかなかったので, 52点解法につての解説は
しません。
• 100 点解法はもちろんわかってますよ !
- 140. 満点解法
• ここではまず, 「平方分割」 という方法について説明する。
• 例として, 次のようなクエリを処理する問題を考えてみよう。
• 数列が 0で初期化されている
• Query 1: a[i] = x とする
• Query 2: 区間 [l, r) の最大値を求める
• 平方分割という方法を使えば, Query 1, Query2 ともに で求められ
る
- 143. 満点解法
• Query 1: a[2] = 5とする
• ⇐ 5, 3, 0 の最大値は 5
• ⇑
• ⇐ 0, 0, 5 の最大値は 5
• ⇑
• ⇐ a[2] = 5 とする
5
5
0 0 5
3
0 3 0
0
0 0 0
- 144. 満点解法
• Query 2: 区間 [2, 8) の最大値を求める
• ⇒ 赤い部分の最小値を求めればよい
5
5
0 0 5
3
0 3 0
0
0 0 0
- 146. 満点解法
• 各ノードに 「ノードが示す区間に 1 が何個含まれているか」 を記録する
ことができればよい
• 区間 [l, r) のビット列を反転させると, 1 の個数は (r–l) - 「区間 [l, r) の 1
の個数」 となる
• では, 実際にやってみよう !
• まず, 最初は1つのノードが示す値について調べてみます。
- 151. 満点解法
• Query 1: 区間 [4, 5) のビット列を反転させる
• ⇒青い部分が O(1) では 1, 3 のどちらになるのか分からない
4
2
0 0 1
2
1 1 0
0
0 0 0
- 152. 満点解法
• 各ノードに 「ノードが示す区間の 1 の個数」 だけを配列に保存すると高
速に動作しない
• そこで方法を考えてみよう。
• ノードAを反転させるとき, ノード A の子の 「ノードが示す区間の 1 の個
数」 は 「反転」 する。
• このことを利用するべきではないか?
- 153. 満点解法
• 各ノードに 2 つの値を記録すればよい
• 区間に含まれる 1 の個数 (完全ではない)
• 各ノードが何回反転されたか
• では, 実際にやってみよう !
- 154. 満点解法
• Query 1: 区間 [2, 3) のビット列を反転させる
[1, 0]
[1, 0]
[0, 0] [0, 0] [1, 1]
[0, 0]
[0, 0] [0, 0] [0, 0]
[0, 0]
[0, 0] [0, 0] [0, 0]
- 155. 満点解法
• Query 1: 区間 [3, 6) のビット列を反転させる
[4, 0]
[1, 0]
[0, 0] [0, 0] [1, 1]
[3, 1]
[0, 0] [0, 0] [0, 0]
[0, 0]
[0, 0] [0, 0] [0, 0]
- 156. 満点解法
• Query 1: 区間 [3, 4) のビット列を反転させる
[3, 0]
[1, 0]
[0, 0] [0, 0] [1, 1]
[2, 1]
[1, 1] [0, 0] [0, 0]
[0, 0]
[0, 0] [0, 0] [0, 0]
- 157. 満点解法
• 今 [2, 1] となっているノードに注目しよう。そのノードの子である [1, 1] と
なっているノードは, 0 から 1 になっている (1 加算されている) が, その
ノードは 1 減算されている。なぜなら, そのノードは 1 回反転されている
ため 「1 から 0 になった」 とみなしているからである。
- 158. 満点解法
• Query 1 は, 各ノードに対して O(1) で処理できることが分かった。
• 次に, Query 2 についてやってみよう。
- 159. 満点解法
• Query 2: 区間 [3, 6) の 1 の数を求める
• ⇒上のノードで全く反転されていないので, 2 である。
[3, 0]
[1, 0]
[0, 0] [0, 0] [1, 1]
[2, 1]
[1, 1] [0, 0] [0, 0]
[0, 0]
[0, 0] [0, 0] [0, 0]
- 160. 満点解法
• Query 2: 区間 [4, 5) の 1 の数を求める
• ⇒青い部分が反転されていることを考えると, 求めるノードも反転されているの
で, 1-0=1 個である。
[3, 0]
[1, 0]
[0, 0] [0, 0] [1, 1]
[2, 1]
[1, 1] [0, 0] [0, 0]
[0, 0]
[0, 0] [0, 0] [0, 0]
- 161. 満点解法
• 区間は, 程度のノードの集合としてあらわされる。
• N=9 で, 区間 [2, 7) を表すとき, [2, 3), [3, 6), [6, 7) に処理をしていけ
ばよい
• Query 2 の場合は, その合計を求めればよい
• 全体の計算量は
- 163. 満点解法
• Segment Tree を使うと,
• Query 1 …
• Query 2 …
• n が大きくなると, SegmentTree の方が実行速度は速い。
• n = 100,000程度の時は, Segment Treeと平方分割がだいたい同じ速度
になる。