AtCoder ABC 127 D - Integer Cards
irisruneです。今日は試しに2記事公開してみました。
アルゴリズムの発想と計算量の抑え方の両面が重要となる問題だと思いました。半分嘘解法です。
package main import ( "bufio" "fmt" "os" "sort" "strconv" ) var sc *bufio.Scanner func nextInt() int { sc.Scan() i, e := strconv.Atoi(sc.Text()) if e != nil { panic(e) } return i } type operation struct { b int c int } type ope []operation func (o ope) Len() int { return len(o) } func (o ope) Swap(i, j int) { o[i], o[j] = o[j], o[i] } func (o ope) Less(i, j int) bool { return o[i].c < o[j].c } func main() { sc = bufio.NewScanner(os.Stdin) sc.Split(bufio.ScanWords) n, m := nextInt(), nextInt() aArray := make([]int, n) for i := 0; i < n; i++ { aArray[i] = nextInt() } var o ope = make([]operation, m) for j := 0; j < m; j++ { o[j].b, o[j].c = nextInt(), nextInt() } sort.Sort(sort.Reverse(o)) cnt := 0 for j := 0; j < m && cnt < n; j++ { for k := 0; k < o[j].b && cnt < n; k++ { aArray = append(aArray, o[j].c) cnt++ } } sort.Sort(sort.Reverse(sort.IntSlice(aArray))) ans := 0 for i := 0; i < n; i++ { ans += aArray[i] } fmt.Println(ans) }
ベースとなる考え方は、元々ある枚のカードとに対応する整数の書かれた枚のカードを合わせた中から、大きい順に枚取り出した整数の合計を求めるというものです。 ただし制約条件がであるため、最終的なカードの枚数は最大で枚を上回ります。つまり安直にカードの集合を足し合わせてソートするとTLEしてしまいます。
それを解消するために取った方法が、集合に足し合わせるカードの枚数に枚という上限を設けるものでした。これによりソート処理でTLEすることはなくなるため問題を解くことができます。
公式解説にあるように、足し合わせるカードを1枚ずつバラさずに集合のまま扱うとすべての集合を足し合わせた上でソートできるため記述はかなり易しくなると思います。
ちなみに、本コードの計算量はとなります。実際は後半がであり、またカード追加の際に枚数で逐一判定しているため公式解説と比べると定数倍遅いと思います。
雑記
- 対談会の記事は先週公開と書いていましたが、今週予定に変更します。