狠狠撸
Submit Search
Square869120 contest #2
?
1 like
?
4,084 views
A
AtCoder Inc.
Square869120 contest #2の解説です。
Read less
Read more
1 of 165
Download now
Downloaded 14 times
More Related Content
Square869120 contest #2
1.
IOI列車で行こう 2 Take the
IOI Train 2 解説
2.
問題概要 ? I, Oからなる文字列
S が与えられる。 ? 文字列 S の部分列のうち, 「IOIOI, IOIOIOIOIOIOIOIのような文字列」 の最大の長さを求めなさい。 ? 1 ≦ |S| ≦ 10,000
3.
部分点解法 ? 先ほど説明した, 「IOIOIのような文字列」
は, I, IOI, IOIOI, IOIOIOI, IOIOIOIOI,... のようになる。 ? そのような文字列をすべて判定することで, できるのではないか?
4.
部分点解法 ? S が
T の部分列であるか判定する 1. ptr = 1 とする 2. Tの1文字目から|T|文字目まで: 3. S の ptr 文字目が今指しているTの文字と等しければ ptr を1加算する 4. ptr=|S|であれば部分列である ? その方法を使って, で判定できる ? 全体の計算量は
5.
満点解法 ? 部分点解法の方法では, |S|=10000
のときにTime Limit Exceededする場 合がある ? もっと高速化する方法はないか?
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問は解かなければあまり現 実的ではないと思いました
8.
結果 / Result ?
First Acceptance… sigma425 (2分1秒) ? 得点分布
9.
B問題 Division 2
10.
問題概要 ? 1以上n以下の整数を書き、それに対して以下の操作をq回行う。 ? 書かれている全ての数に対して、a[i]で割り切れるのであればその 数をa[i]で割った数に書き換える。ただし、a[i]はi回目の操作におけ る割る数である。 ?
最終的に1が何個書かれているか、求めてください。 ? ただし、aの入力はa[1]からはじまりa[q]で終わるものとして考えます。
11.
問題概要 ? 小課題1(25点)?1≦n≦1000000,1≦q≦24 ? 小課題2(75点)?1≦n≦10^13,1≦q≦24 ?
どちらの小課題でも3≦a[i]≦50である。 ? うさぎは2で割るのが嫌いなため、a[i]=2ではない。
12.
例 ? 例えば、n=10,q=3,a={3,4,6}のとき、 ? 最終的な1は{1,3,4}からの3つになります。 割る数
1 2 3 4 5 6 7 8 9 10 3 1 2 1 4 5 2 7 8 3 10 4 1 2 1 1 5 2 7 2 3 10 6 1 2 1 1 5 2 7 2 3 10
13.
部分点解法(25点) ? 愚直に計算をします。 ? 配列を使ってx[i]=iにまず初期化します。x[i]というのは、i番目 の数は今現在何なのかということを表します。 ?
q回の操作を以下のように行います。 ? x[1]からx[n]まで順番に見ていきます。その数字がa[i ](i回目の 操作の場合)で割り切れたらその数字を1回だけa[i]で割ります。
14.
部分点解法(25点) ? コードでは、if(x[j]%a[i]==0){x[j]/=a[i]}ということです。 ? 4ページ目の表のように操作することをイメージすればわかりやすいで しょう。 ?
計算量は、各クエリにつきO(n),クエリがq個あるのでO(nq)となります。 n=1000000,q=24の場合2400万回となり、間に合います。 ? しかし、小課題2ではn=10^13,q=24が最大だから、計算量は10^14回を超 えてしまいます。?TLEをします。
15.
考察1 ? Q≦24であることを利用できないか? ? 割れるなら「割る」、割れないなら「割らない」なので、Π(a[i]また は1)※Πはi=1からQまでの範囲で、しか可能性がないので は? ?
例えば、a[i]={3,4,6}のとき、以下の8通りしか可能性はない。 1*1*1=1,1*1*6=6,1*4*1=4,1*4*6=24, ? 3*1*1=3,3*1*6=18,3*4*1=24,3*4*6=72
16.
考察1 ? a[i]をいくつか選んだときの積であれば、その「選んだ場所」だ け割り、それ以外の場所では割らないことになる。 ? そうでない場合、どこで割っても1にならない。 ?
なぜなら、割るときは必ずa[i]以外で割ってはいけないからで ある。また、a[i]を選んだ時の積の分だけ割れるので、それが ある数Cと一致している場合のみC/積=1になるからである。 ? ?考察は正しい
17.
満点解法 ? 考察より、2^q通りしか可能性はないことが分かった。 ? ?これを全列挙できる!! ?
まず、a[i]で割るか割らないかを0か1かで表される配列bのi番 目の要素に記録しておく。 ? h=0から2^q-1のときまでループし、そのときのb[i]は ? b[i]={h/(2^(i-1))}%2となる。
18.
満点解法 ? そして、最初sum=1として、b[i]が1のときsumにa[i]をかけます。 (1≦i≦q) ? sumで最後1になるか試して、なれば答えに1を足します。 ?
そのようにすれば、どのa[i]を選ぶかを全通り、重なりがなく調 べることができる。JOI2007-08予選5:Osenbeiなどが解法として は似ている。
19.
満点解法 ? 通り数が2^q通り、1つの数字から始めると1になるかを調べるクエリ がO(q)だから、計算量はO(q*2^q)となる。 ? q=24のとき、約400,000,000回の計算が必要となる。 ?
制限時間が5secだから、定数倍が速いか普通だと、C++などの実 行速度の速い言語ではギリギリ通ります。 ? ちなみに、この解法での私のコードの実行時間は2354msでした。 ? しかし、定数倍が遅かったり、JAVAなどのやや実行速度の遅い言 語だと通らない。
20.
考察2 ? 完全な全列挙ではなく、後ろから考えて工夫して全探索できる のではないか? ? ?Queueを使おう! ?
Queueについては、 ? http://www.cc.kyoto-su.ac.jp/~yamada/ap/queue.html ? を参照してください。
21.
満点解法2 ? まず、最初に2つの引数を持つQueueを用意し、第1引数を現時点 での数、第2引数を「何個目のクエリまで終わったか」とします。 ? そして、Queueに(0,q)を入れます。その後、以下のループをQueue の大きさが0になるまで続けます。 ?
Queueの先頭の第1引数をc1,第2引数をc2とします。 ? c2=0となった時点で「全ての処理が終わっている」ので、ループか ら抜けます。 ? そのあと、Queueをポップします。
22.
満点解法2 ? 割ってc1になる場合 ? c1*a[c2]がqを超えない場合、可能です。(その場合、Queueに (c1*a[c2],c1-1)をプッシュします。 ?
c1*a[c2]は当然a[c2]で割り切れるので、前から考えると …→a[c2]*c1→c1→…となります。 ? 割らずにc1になる場合 ? c1がa[c2]で割り切れるとc1→c1/a[c2]に自動的になってしまうので、不 可能です。それ以外の場合、Queueに(c1,c2-1 )をプッシュします。
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のサイズとなります。 ? グレーの部分は枝刈りされたものを示しています。
24.
満点解法2 ? 状態数は最大で2^(q+1)通り、各状態につきO(1)かかるので、 計算量は最大でO(2^(q+1))となります。 ? q=24のとき、最大約3000万回の計算が必要ですが、満点解法 1よりは明らかに速いです。 ?
私が書いたコードだと、35msで通りました。 ? JOIでいう難易度5(満点解法2は6)くらいだと思います。
25.
結果 ? FirstAcceptance:sigma425(8分06秒) ? 得点分布
26.
おしまい
27.
C問題 何通りの分割方法がある?
28.
問題概要 ? 整数nが与えられる。 ? nを文字列に変換したものをSとする。 ?
Sをいくつかの部分に分割する。 ? それを全て数字に変換するとき、和がD以内でなければならな い。ただし、各数字は0から始まってもよい。 ? 何通りの分割方法があるか、求めてください。
29.
問題概要 ? 小課題1(10点) ? 通り数は1通り以下である。 ?
小課題2(30点) ? n≦10,000,000,000を満たす。 ? 小課題3(60点) ? N≦10^100を満たす。
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で割った余りで求めなければならない。
31.
注意事項 ? 小課題3では、n≦10^100と非常に大きいので、C++などでは 整数nを文字列として受け取らなければならない。 ? JAVAやC#などでも、BigIntegerという巨大な整数を用いる型を 利用しなければならない。 ?
64ビット型整数に収まる整数は最大约9*10镑18である。
32.
小課題1(10点) ? 小課題1では、通り数は0か1しかありません。 ? 「通り数が1の場合」は、どれか1つの方法が存在するということです。 ?
一番和が少なくてできる方法は、1桁ごとに分割するという方法です。 ? なぜなら、最初すべて1桁ごとで、ある2つの隣り合った数字を合成 すると、10の位がa,1の位をbとすると、10a-a=9aだけ和が増えてしま います。
33.
小課題1(10点) ? ?よって、「各位の数字の和」が考えられる各数字の総和として最 小となります。 ? 答えは0か1なので、「各位の数字の和」がD以下ならば「1」、Dを超 えていたら「0」となります。 ?
各位の数字の和を求める方法は、整数をまず文字列に変換し、最 初の文字から順番に見ていきます。 ? I文字目が「1」であれば1,「 2」であれば2…をsumに加算します。最 終的なsumの値が各位の数字の和となります。
34.
小課題2(40点) ? 小課題1の方法では、答えが2通り以上の場合には対応できま せん。なぜなら、1桁ずつ分割する方法でできる場合、少し2桁 以上の数字を入れても条件を満たす場合があるからです。 ? 小課題2(30点)はn≦10^10までです。 ?
?これを利用できないか? ? できます。
35.
小課題2(40点) ? nはせいぜい10桁です。 ? 切る場所(=桁と桁の間で分けるか)はTrueかFalseの2通りなので、 2^|n|でできます。 ?
実際桁と桁の間は|n|-1個しかないので、2^|n|-1通りを調べ上げる 必要があります。 ? 例えば、n=1355,場所={1,0,1}(1=True,0=False)のとき、1番上の位を 0桁目とするとき、0桁目と1桁目で分け、2桁目と3桁目で分けること になります。?{1,35,5}の3数に分割されます。
36.
小課題2(40点) ? i=0から2^(|n|-1)まで以下のような操作を繰り返しますが、i桁 目とi+1桁目の間を分けるかどうかを表す変数をb[j]とします。 ? b[j]={i/(2^j)}%2(0≦j≦|n|-2)となります。 ?
配列bの数値が分かれば、どのようにnが分割されているかもわ かります。 ? それが分かれば、分割されている各数字の総和を求めてそれ がD以下であれば答えに1を加算します。
37.
小課題2(40点) ? 例えば、D=50,n=1355で{1,35,5}と分割された場合その総和は41だから答えに1 を加算します。 ? 計算量は調べ上げる通り数が2^((nの桁数)-1)通り、1つの分割状態につき ?
O(nの桁数)かかるので、計算量はO((nの桁数)*2^((nの桁数)-1))となります。 ? ここまででは、AOJ1237:Shredding Companyという問題によく似ています。 ? n=9,999,999,999のとき、計算量は約5000回となります。 ? しかし、n=10^100のとき、計算量は約10^32回となり、明らかにTLEします。
38.
考察1 ? D≦100,000であることを利用できないか? ? 1桁目から順に通り数を見ていきDPで解けないか? ?
どこまで見終わったか、今までの和、通り数と3つの要素が分 かればできるのではないか? ??DP(動的計画法)
39.
満点解法 ? 考察でも示しましたが、「どこまで見たか」「今までの和」「通り数」の3つの 要素が必要です。 ? 1つ目は|n|以下、2つ目はD以下、3つ目は10億7以下なのでdp[どこまで 見たか][今までの和]として通り数mod
1,000,000,007を格納するのが最適 です。 ? メモリはint型10,000,000個だから足ります。 ? まず、dp[0][0]=1とします。 ? そして、次のページの操作をrep(i,1 ~n),rep(j,0 ~D)として繰り返します。
40.
満点解法 ? dp[i][j]の値を更新するとき、(最初にsum=0に初期化します。) ? まず、t=0とします。ループのたびにtに1を足します。 ?
10^t*(i-t桁目の値)をsumに足します。 ? sumがDを超えるかi-tが0未満になるとループから抜けます。 ? dp[i][j]にdp[i-t][i-sum]を足します。これは、i-t桁目までを分割した時 の和がi-sumで、そのあと、t桁分分割せずに数字を「今までの総和」 に足し、そこで(i-1桁目とi桁目の間で)分割するを意味します。
41.
満点解法 ? そこで、1点注意事項があります。 ? 0がいくつか続いた後に1がくると、一度に10^20とかいう巨大な数 が足されてしまう可能性があるので、i-t桁目が1以上でかつt≧7の ときループから抜けるようにする必要があります。(オーバーフロー には注意すること。) ?
結果は、Σdp[n][i](0≦i≦D)となります。 ? n-1桁目(最後の桁)まで見終わるということは「全ての桁を見終わっ た」=「それ以上足されない」ことを意味します。
42.
満点解法 ? 最後に1,000,000,007で割るのを忘れないようにしましょう。 ? 計算量は、ループにO((nの桁数)D),一度にO(Dの桁数)くらいかかるので、計算 量はO((nの桁数)*D*(Dの桁数))と見積もれますが、0が続くケースの場合、 ?
最大でO((nの桁数)^2*D)となります。定数が1/2くらいつくので制限時間5secな ら間に合います。 ? 工夫してdp[i][j]が1以上のときdp[i+t][j+sum]に足す方法でやれば、0が続く場合 でも対処できます。 ? この場合、sumはi桁目からi+t桁目までの数字列を1つの数字として表したときの 値となります。
43.
満点解法 ? 想定解は約500msです。 ? 工夫してdp[i+t][j+sum]の形でやった場合です。 ?
ちなみに、小課題1は難易度2,小課題2は難易度5,小課題3は 難易度6~7くらいだと思います。 ? コンテストお疲れさまでした。
44.
結果 ? First Acceptance:piroz95(24分43秒) ?
得点分布
45.
おしまい
46.
D問題 2016
47.
問題概要 ? 整数nが与えられます。 ? n以下の数字の中で約数の個数がが最大となる数の約数の個 数と、この約数の個数を持つ数の中で最小の整数を求めなさ い。 ?
ただし、最初にクエリの数Qが与えられて、Q回だけ整数nが質 問されることになります。
48.
問題概要 ? 1≦q≦10,000を満たす。 ? 小課題1(8点)…1≦n≦10,000を満たす。 ?
小課題2(34点)…1≦n≦1,000,000,000を満たす。 ? 小課題3(58点)…1≦n≦10^17を満たす。 ? 小課題3では特に、オーバーフローに注意すること。
49.
例 ? 例えば、n=100の場合、 ? 最大の約数は12個あります。 ?
約数が12個の、100以下の整数は、60,72,84,90, 96があります が、60の方が小さいので60の方を出力します。 ? 答えは、12と60を空白区切りで出力することになります。(この 場合)
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
51.
小課題1(8点) ? 自明な探索解で解けます。 ? n≦10,000と非常に少ないため、クエリごとに処理する必要はありま せん。 ?
最初にn=1,2,3,4…10000のとき約数が何個になるのかを記録した配 列をaとすると、 ? a[i]=max(a[i-1],a[i])とします。 ? そうすると、nが与えられたとき答えはO(1)で求めることができます。 答えはa[n]です。
52.
小課題1(8点) ? 1つの数字の約数の個数を求めるのにO(n)、かつn個の数字に対してこ れを求める必要があるので、計算量はO(n^2)となります。 ? 小課題1でのnの最大は10,000なので、計算量は約1億回です。?時間 制限3secであれば間に合います。 ?
ちなみに、aは下表のようになります。 整数n 1 2 3 4 5 6 7 8 9 10 11 12 13 もとのa[i] 1 2 1 3 2 4 2 4 3 4 2 6 2 答えのa[i] 1 2 2 3 3 4 4 4 4 4 4 6 6
53.
考察1 ? n≦1,000,000,000であれば、小課題1の解法であれば明らかに TLEしてしまいます。 ? また、配列をを1,000,000,000個も置くと、MLEしてしまうので、ク エリごとに処理する必要があります。 ?
Q≦1,000なので、1クエリにつき可能な計算量は最大で約 300,000回です。
54.
考察1 ? ?約数を全て調べるひまがありません。 ? ?問題は「約数を最大化しろ」なのでDFSでできるのでは? ?
素数を列挙し、掛けていきnを超えるまでつづけるのがいいの では? ? 図は次のページを参照してください。
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 のように 続きます。
56.
小課題1(8点)解法2 ? このようにDFSでも解けます。 ? 方法としては、 ?
素数を{2,3,5,7,11,13…sqrt(n)}くらいまで列挙し、 ? nを超えるまで掛け続ける。 ? nを超えたら1手前に戻る。 ? それでもすべての場合でダメな場合さらに1手前に戻る。 ? 約数が最大のときの整数をmin,maxなどを使い求められる。 ? 1ページ前を参考にすること。
57.
小課題1(8点)解法2 ? その場合、計算量的にはn≦10,000では間に合います。 ? それに少し工夫を加えれば、小課題2が通ります。 ?
※注意事項 ? DFSは、スタックや再帰を使えば実装できます。
58.
考察2 ? 全探索する必要ないのでは? ? そもそも素因数3が0で5が1よりも3を1にした方が数が小さくなり かつ約数の個数も変わらないのでこちらの方が得なのでは? ?
?一度素因数0の場所が現れたらそれ以降は0なのでは? ? ×{3,0,1,0,1…},〇{3,1,1,0,0…}
59.
小課題2(42点) ? 考察2より、次のように全探索することができます。 ? 素数を{2,3,5,7,11,13…47}まで列挙します。 ?
ただし、2*3*5*7*11*13*…*47≒6.14*10^17だから、47までしか 必要がないです。 ? 考察1のようにDFSをしますが、個数0からではなく1から探索す るようにします。
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)
61.
小課題2(42点) ? 計算量的にはそれで小課題2には通ります。 ? しかし、小課題3では現実的な時間にはなりますが、TLEをして しまいます。 ?
そこで、さらに考察をする必要があります。
62.
考察3 ? 小課題3では、今までの方法だとTLEします。 ? 想定時間は約11secくらいです。 ?
よく見てみると、{2,3,5}={1,2,0}のようになっている場合があります。 ? これを{2,1,0}にスライドした方が数は少なくなり、約数は同じなので こちらの方が効率的 ? ?{2,3,5,…}を昇順にソートさせたとき一番効率的
63.
考察3 ? つまり、a(2)≧a(3)≧a(5)≧a(7)≧…となるようにプログラムを組 めばよいと考えられます。 ? ちなみに、a(n)とは、素数nで何回割れるかということです。 ?
このようにすれば、さらに时间が短くなります。
64.
満点解法 ? 考察3を利用します。 ? 再帰またはDFSの、「何回掛けるか」の範囲を ?
1から「前の掛けた回数(1つ前の素数を何回掛けたか)」までにします。 ? また、1回nを超えてしまったら、その次の素因数以降探索せずにもう1回 戻るという方法も使えます。(つまり合計2回もどるということ) ? 例えば、n=30のとき、次ページのようになります。 ? {2,3,5}=(整数,約数)の形で表します。
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回戻り の途中を表し ます。
66.
満点解法 ? このように、工夫をして計算量を減らすことができます。 ? この場合、問題で問われているのは「約数の最大化」なので、 全てを調べ上げる必要はありません。 ?
このようなアルゴリズムを「ヒューリスティック探索」ともいいます。 ? 想定解は約400msです。
67.
参考問題 ? JOI 2009-10予選6
「方向音痴のトナカイ」 ? AOJ 0190 「11パズル」 ? AOJ ALDS1_13_C 「15パズル」 ? AOJ 1128 「square carpets」
68.
結果 ? First Acceptance:nuip(14分47秒) ?
得点分布
69.
おしまい
70.
E問題 部分文字列 / Substrings 解説
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
81.
満点解法 ? それを利用して通すことができる ? 計算量は
O(| S| log^2 |S|) なので間に合う
82.
結果 ? First Acceptance
… climpet(6分51秒) ? 得点分布
83.
Range Sum Queries 解説
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
87.
0点解法 ? 問題文の通りそのままやる ? 1回の操作につき
かかる ? 全体の計算量は ? a, b,c が 1,000であることを考えるとTime Limit Exceededしてしまう。
88.
部分点解法(12点) ? もっと高速化する方法はないか? ? 実は,
d[i] を求める時にd[i-1] の値を利用できる ? (右辺は current ) ? ? ? 計算量は O(ac)なので小課題1には通る
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 の経路の総数について考えてみましょう
91.
考察1 ? 縦に進む時をX, 横に進む時をYとする。 ?
そのとき, XがH個, YがW個 あります。 ? 経路の総数は, H+W個のなかからH個を選ぶので 通りとなります。
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) で求められます ? では, どのようにして を求めるのか? ? 上の方法を利用すれば で求められる。 ? もっと高速化する方法はないか?
96.
満点解法 ? であるから, その関係について 調べてみると,...
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」
99.
結果 ? First Acceptance…
snuke(25分10秒) ? 得点分布
100.
G問題 道とN個のAtcoder社
101.
問題概要 ? N個のAtcoder運送会社の工場が存在する。 ? その座標は(xi,yi)である。(入力される。) ?
工場と工場を結ぶ道をできるだけ建設したいが、工場以外で 道と道は交差してはならない。 ? 最大で何個の道を建設できるか求めなさい。
102.
問題概要 ? 小課題1(14点)…1≦n≦4を満たす。 ? 小課題2(50点)…1≦n≦100を満たす。 ?
小課題3(36点)…1≦n≦2,000を満たす。 ? どの小課題でも、3工場は一直線上に並ばない。 ? また、0≦xi,yi≦1,000,000,000である。
103.
例 ? n=4,座標={(0,0),(1,1),(0,1),(1,0)}のとき、 ? 最大で5本の道を建設できる。
104.
小課題1(14点)解法1 ? 自明な探索解です。 ? n≦4のとき、線は最大で6本しか引くことができません。 ?
よって、どことどこが結ばれているか、2^6通りを列挙する方法でで きます。 ? 結ばれている線に交差がない場合、 ? maxn=max(線の本数,maxn)とします。 ? 答えは、maxnの値になります。
105.
小課題1(14点)解法2 ? 貪欲でも解けます。 ? まず、n=1のとき、道は0個建てられます。 ?
次に、n=2のとき、道は1個建てられます。 ? 次に、n=3のとき、3工場が三角形の形になるため、道は3個建てら れます。 ? 次に、n=4のとき、道が5個建てられる場合、6個建てられる場合の2 通りに分かれます。
106.
小課題1(14点)解法2 ? ある3点を選んで、残りの1つの点が3つの点からできる三角形 に囲まれる場合、道は6個建てられます。 ? どのように3点を選んでも囲まれない場合、道は5個しか建てら れません。 ?
次のページの図を参照してください。
107.
小課題1(14点)解法2 ? 道が6本のとき/道が5本のとき(実際は工場は点として考える)
108.
考察1 ? 小課題2は、1≦n≦100です。 ? 小課題1と比べて、nが一気に大きくなるので、到底全探索だと間に 合いません。 ?
多項式時間で求めるとしても、O(n^4)程度またはそれ以下で求める 必要があります。 ? ?解法としてはGreedyが考えられます。 ? 辺の本数の最大を求めるのでDPではできにくいです。
109.
考察1 ? 三角形を作ります。 ? 道をn*(n+1)/2通り列挙し、その時点で道が引けるならば道を 建て、引けないならば道を建てません。 ?
証明としては、三角形の辺をつながるところにどのように移動し たとしても、四角形を作ることはできないからです。 ? ?道の数は四角形をなくし、三角形だけにしたときに最大
110.
考察1の図 ? 四角形がある図/三角形しかない図
111.
考察1の図 ? 辺の移動?新しく四角形は現れない
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のとき結ぶ ? このような方法でやると、無駄な四角形の部分がなくなる
113.
小課題2(64点) ? {a,b}を求めるのに最大でO(n^2)かかります。 ? 実際は線分の数は大体nに比例し、平均で3nくらいになります。 ?
そして、{a,b}はn^2回呼び出すので、最大でO(n^4)となります。 n=100の場合、定数が(?)*(?)=(?)くらいつくので、約2500万 回?間に合います。 ? しかし、n=2000のときはTLEしてしまいます。
114.
考察2 ? どのような順序で調べてもよいが、線分の交差判定をしている時間 が無駄 ? ?何が使えるか? ?
方法としては、外から順番に道を引いていくが、印をつけた点を除 く点集合のConvex_Hullの周りは全て道で囲むことができる ? そして、Convex_Hullになった点は印をつける ? これを繰り返していけば、最終的にすべての点に印がつく
115.
考察2 ? 以下のような図になる。(左?右)
116.
考察2 ? 前の図で、2つのConvex_Hullで囲まれた凸多角形の間にも辺 が結べる ? それに対して全探索をする場合、前よりは計算量は落とせるが 小課題3は通らない ?
2つの凸多角形の間に何本の点が引けるのかを高速に求めた い
117.
考察2 ? これは以下のようになる。 ? a頂点からなる凸多角形とb頂点からなる凸多角形の場合 ?
ただし、前者の方が外側とする。 ? b=1のとき、a個の道が建てられる。 ? b≧2のとき、a個の道が建てられる。 ? 証明は、次のページを参照してください。
118.
考察2の証明 ? まず、b=1のときb側の頂点からa側の頂点に1つずつ道が引けるの で、合計でa個道が引けます。 ? そして、b≧2(a≧b)のとき、交点ができないようにa側の点から1つず つ道を引くと、b個の四角形ができます。 ?
ただし、n角形は四角形n-3個分とします。 ? 四角形1つにつき1本追加で道が引けるので、追加で道をb個建て ることができます。よって、合計でa+b個の道を建てられます。 ? a≦bのときもaとbを逆転すれば証明できます。
119.
考察2の証明 ? b=1のとき/b≧2のときは以下の図のようになります。
120.
満点解法 ? 考察2を利用して解けます。 ? 解法としては、Convex_Hullを求めて、その点集合に印をつけ ます。そのとき、sumに点集合の数を加算します。 ?
そして、このConvex_Hullが2つ目以降の場合、1つ前の Convex_Hullの点集合と結べる道の数をsumに加算します。 ? sumの最終的な値が答えとなります。
121.
満点解法 ? 考察2の証明の右のほうの図では、答えは4+3+7=14個となり ます。 ? 計算量は、Convex_Hullを求めるのに最大でO(n^2
logn)かかり、 sumに加算するのに最大でO(n)かかるため、計算量は最大で O(n^2 logn)となります。 ? n=2,000のとき、計算量は最大で約4,000万回?間に合います。 よって、合計100点が得られます。
122.
満点解法 ? この問題は、H問題と同じくらい、このsquare869120Contest#2 で1,2を争うくらい難しい問題だと思います。 ? ちなみに、私は考えるのに2日間もかかってしまいました。 ?
想定解は66msです。 ? JOIの難易度表でいう難易度10くらいでしょう。
123.
結果 ? First Acceptance:DEGwer(18分07秒) ?
得点分布
124.
おしまい
125.
H問題 Counting 1's 解説
126.
はじめに ? square869120Contest #2
にご参加いただきありがとうございます。 ? 私は解法を考えるのに 2 日かかりましたが, G問題はもっとかかりました。 ? 問題を考えてから思ったんだけど, JAGAsia 2012 にも Counting 1's とい う問題があったが, 全然違う問題である。そもそもJAGの方のCounting 1'sは難易度が高すぎます。
127.
はじめに ? E869120, square1001の2人で合計20-30問くらい
(約 10-15問ずつ) の 問題の候補を出しましたが, 2人で話し合って合計8問 (4+4) を厳選しま した。そして, この8問を出すことにしました。 ? 解法を考え終ってからいざ実装すると約40行で書けてしまって 「えっ、こ れが H 問題なのか?」 と思いました。
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
134.
部分点解法(8点) ? 何も工夫をしないでやります。 ? 1つのクエリに対して
O(N) で処理します。 ? 全体の計算量は O(NQ) ? ?これだけで 8 点もらえる !
135.
部分点解法 (16点) ? 制約 ?
1≦N≦100,000 ? 1≦Q≦100,000 ? Query 2 は 1,000 個以内 ? そのままでは Query 1 にO(N), Query2 にO(N) かかっているので間に 合わない ? Query1 の実行速度を速くするためにはどのような方法を使えばよいか?
136.
部分点解法 (16点) ? 次のようなクエリに置き換えることもできる ?
Query 1: 区間 [l, r) に 1 加算する ? Query 2: 区間 [l, r) の中で 2 で割ると 1 余るようなものの数を求める ? 「いもす法」 という方法を使うと Query1 が O(1) でできる
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 ともに で求められ る
141.
満点解法 ? N =
9 のとき 0 0 0 0 0 0 0 0 0 0 0 0 0
142.
満点解法 ? Query 1:
a[4] = 3 とする 3 0 0 0 0 3 0 3 0 0 0 0 0
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
145.
満点解法 ? そのようにすれば, Query1
を で終わらせることができる ! ? 実際には, Query 1 には O(1) しかかかっていない
146.
満点解法 ? 各ノードに 「ノードが示す区間に
1 が何個含まれているか」 を記録する ことができればよい ? 区間 [l, r) のビット列を反転させると, 1 の個数は (r–l) - 「区間 [l, r) の 1 の個数」 となる ? では, 実際にやってみよう ! ? まず, 最初は1つのノードが示す値について調べてみます。
147.
満点解法 ? Query 1:
区間 [2, 3) のビット列を反転させる 1 1 0 0 1 0 0 0 0 0 0 0 0
148.
満点解法 ? Query 1:
区間 [3, 6) のビット列を反転させる 4 1 0 0 1 3 0 0 0 0 0 0 0
149.
満点解法 ? Query 1:
区間 [0, 3) のビット列を反転させる 5 2 0 0 1 3 0 0 0 0 0 0 0
150.
満点解法 ? Query 1:
区間 [3, 4) のビット列を反転させる 4 2 0 0 1 2 1 0 0 0 0 0 0
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 の場合は, その合計を求めればよい ? 全体の計算量は
162.
満点解法 ? SegmentTreeを使って同様の処理をすることもできる ? 平方分割は,
3段になっていて, 1つのノードの子が √(n) 個ある。 ? Segment Tree は, logn 段になっていて, 1つのノードの子が logn 個ある。 ? 同じような方法で, Query1, Query2 を処理できる。
163.
満点解法 ? Segment Tree
を使うと, ? Query 1 … ? Query 2 … ? n が大きくなると, SegmentTree の方が実行速度は速い。 ? n = 100,000程度の時は, Segment Treeと平方分割がだいたい同じ速度 になる。
164.
満点解法 ? ちなみに, 私が最初に思い付いた解法がSegment
Treeによる解法で, 実 装は本当に簡単でした。 ? 平方分割による解法はコンテスト 5 日前に思い付きました。
165.
結果 ? First Acceptance
… yosupo(5分13秒) ? 得点分布
Download