見出し画像

Go言語で挑む競プロ #18

久しぶりに過去問を解いていこうと思う。
過去問をnoteに書くのはいつぶりだろうなぁって思って振り返ってみたら、8月18日が最終投稿だった...もう少しで一か月たってしまう...
もっと頑張っていかないと!

ってことで、今回はABC132のC問題を解いていこうと思う。どんどん解いていないC問題を埋めていこう!

ABC132Cの問題

問題文
高橋君は、 N 個の競技プログラミング用の問題をつくりました。
それぞれの問題には 1 から N の番号がついており、問題 i の難易度は整数 di で表されます(大きいほど難しいです)。
高橋君はある整数 K を決めることで、難易度が K 以上ならば「 ARC 用の問題」難易度が K 未満ならば「 ABC 用の問題」という風に、これらの問題を二種類に分類しようとしています。
「ARC 用の問題」と「ABC 用の問題」が同じ数になるような整数 K の選び方は何通りあるでしょうか。

制約
- 2≦N≦10^5
- N は偶数である。
- 1≦di≦10^5
- 入力は全て整数である。

アルゴリズム

これは簡単に解けそうだね。アルゴリズムはこんな感じ。

1. 問題を難易度の昇順に並び替える
2. 問題をちょうど二分した後に、以下の値を取得する
 ・前半部分のうち最も難しい難易度の値
 ・後半部分のうち最も易しい難易度の値
3. 取得した値の差分が解答となる

とてもシンプルだね。
kの値の数は、二分した際の境界値の間に存在しうる値の数を求めればよい。そして、xからyの間に存在しうる値の数は、y-x となるため手順3で求めることができるはずだ。

例を見てみて正しさをチェックしてみよう。

難易度の数列: 1, 4, 4, 6, 7, 9
二分すると : 1, 4, 4 |  6, 7, 9
可能なkの値: 5, 6
解答    : 6 - 4 = 2(個)

上の例だと、二分する際に取ることのできるkの値は5と6の二つとなる。そして、手順2で取得した値は、4と6となるので、6-4=2でkの個数と等しくなることがわかる。

あとは、これを実装したら完成だ!

解答

最終的には、以下のコードに。

package main

import (
   "bufio"
   "fmt"
   "os"
   "sort"
   "strconv"
)

func main() {
   var n int
   s := wordScanner()
   scanInts(s, &n)

   l := make([]int, n)
   for i := 0; i < n; i++ {
       scanInts(s, &l[i])
   }

   sort.Ints(l)
   fmt.Println(l[n/2] - l[n/2-1])
}

func wordScanner() *bufio.Scanner {
   s := bufio.NewScanner(os.Stdin)
   s.Split(bufio.ScanWords)
   return s
}

func scanInts(s *bufio.Scanner, vals ...*int) {
   for i := range vals {
       s.Scan()
       n, _ := strconv.Atoi(s.Text())
       *vals[i] = n
   }
}

今回の問題はとても簡単だった。問題もアルゴリズムもシンプルでスムーズに解くことができた。

この調子でどんどん頑張っていくぞ!

========

前回の競プロへの挑戦はこちらから。


この記事が気に入ったらサポートをしてみませんか?