SlideShare une entreprise Scribd logo
1  sur  12
解説:吹奏楽部
技術室奥プログラミングコンテスト 問題F
問題を整理してみる
• 分母が2~N+1の、既約分数の位置に奏者が立っている
• ある審査員の位置から、ある距離内にいる人間の数がわかっている
• その中で、最も遠い奏者の吹く楽器の番号が知りたい。
• →立っている位置を既約分数で表した時の分母が知りたい。
基本方針
• 審査員が見る距離を二分探索
• 舞台の端からある位置までにいる奏者の数を高速に求めたい
部分点解法
• ファレイ数列を使うと、分母が2~N+1までの既約分数を小さい順で
で列挙することが可能。既約分数の数はせいぜいN^2なので、
O(N^2)で求められる。
• 舞台の端からある位置までの奏者の人数を
二分探索を用いることでO(LogN)で求められる。
• よって、見る距離の二分探索にかかるのはO(logN*logN)
• 審査員全員分合わせて、O(Mlog^2N)
• 全体オーダーは、O(N^2+Mlog^2N)
満点解法
• 全ての既約分数を列挙する時間もメモリもない。
• 既約分数の個数を一斉に求める方法を考える
• 既約分数に限らなければ、ある範囲にある分数の個数を
O(N)で計算できる。
• それぞれの分母ごとに、範囲内の分数の個数にある係数をかけると
考えてみる。
満点解法
• 分母𝑖に対応するある係数𝑘𝑖を考える
• たとえば、N=5の場合において、
𝑘2 = −1, 𝑘3 = 0, 𝑘4 = 1, 𝑘5 = 1, 𝑘6 = 1 としてみる
• ここで、1/2以下の、分母N+1以下の分数の個数と、それに上の係数
をかけたものを考えてみる。
分母 2 3 4 5 6
個数 1 1 2 2 3
係数 -1 0 1 1 1
かけたもの -1 0 2 2 3
満点解法
• ここで、かけたものの合計を考えてみると、6になっている。
• これは、1/2以下の、分母が2~N+1の既約分数の個数と
一致している。
• これは偶然ではなく、1/2以外でも同じように成り立つ。
• なぜか?
分母 2 3 4 5 6
個数 1 1 2 2 3
係数 -1 0 1 1 1
かけたもの -1 0 2 2 3
満点解法
• たとえば、1/2-epsから1/2になった時の変化を考えよう。
• この時、分母が、2,4,6の分数が一個ずつ増える。
• それぞれの係数は、-1,1,1なので、合計で一個増える。
• 同様に、1/3でも3/5でもどんな既約分数の位置においても、
増える数の係数の合計は1になる。
• このような性質があるので、係数をかけたものを足すと
既約分数の個数になっている
• N=5の場合に限らず、与えられるNに対してこのようなうまい係数を
求めれることができればよい
満点解法
• どうやって作るか
Int k[N];
for(i=N+1;i>=2;i--){
k[i] = 1;
for(j=i*2;j<=N+1;j+=i)
k[i] -= k[j];
}
こんな感じでやるとうまくいく
満点解法
• どうしてこれでうまくいくか
• ある既約分数A/Bを考え、A/B-epsからA/Bへの変化を考える
• この時、個数が増える分数は、
分母がBの整数倍になっているものである
• 先ほどのコードでの係数の求めからわかるように、
分母がBの倍数の係数の合計は、必ず1になる
• 一つ既約分数が増えるたびに、係数をかけた分数の個数の合計は
1増えるので、これでうまくいく
満点解法
• 係数の計算は、O(NlogN)
• 係数を使うことによって、ある範囲の既約分数の個数を
O(N)で求められる。
• あとは部分点解法と同様に、審査員それぞれについて二分探索
• 見る範囲の端の処理に気を使いましょう
• 全体オーダーはO(MNlogN)
おわりに
• O(MNlog^2N)を落とそうと思っていましたが、通されました。

解説:吹奏楽部