技巧
贪心 堆
思路
本质上是将问题转换为单维度贪心(即不要去影响前面的决定)
这个题目存在两个维度 1 攻击力 2 容忍度 按照前面的说法,选人可能会影响到前面已经做了的决定,所以暂时行不通。
这里需要把问题换个角度思考 => 如何固定或者说相对固定一个维度呢?
我们先将容忍度s 按照降序处理。 然后另外再开一个容器用于收集当前已经选定的士兵
这么做的好处是将整个容忍度模型转化成了一个一次函数 ===》 \ 而且随着时间的推移我们能够知道收集容器的容量应该会越来越少
很显然,用堆结构来定义这个容器很合适 (战斗力维度组成的小根堆, 方便看情况舍弃或保留元素)
然后不断去更新堆结构找出最大值即可
这种做法也有说法叫做“可以后悔的贪心” 即在后续的决定中改变到了前面的决定。 不过整个流程中所有过程的值都被合理准确的记录下了。
实现
package main import ( "bufio" . "fmt" "io" "os" "sort" ) type Soldier struct { v, s int } func siftDown(heap []Soldier, last int) { curr := 0 for curr < last { min := curr if 2 * curr + 1 < last { if heap[2 * curr + 1].v < heap[min].v { min = 2 * curr + 1 } if 2 * curr + 2 < last && heap[2 * curr + 2].v < heap[min].v { min = 2 * curr + 2 } } if min == curr { break } heap[curr], heap[min] = heap[min], heap[curr] curr = min } } func siftUp(heap []Soldier, i int) { for i != 0 && heap[i].v < heap[(i-1) / 2].v { heap[i], heap[(i-1) / 2] = heap[(i-1) / 2], heap[i] i = (i-1) / 2 } } // https://ac.nowcoder.com/acm/problem/50439 func NC50439(_r io.Reader, _w io.Writer) { in, out := bufio.NewReader(_r), bufio.NewWriter(_w) defer out.Flush() var n int Fscan(in, &n) arr := make([]Soldier, n) for i := 0; i < n; i++ { Fscan(in, &arr[i].v, &arr[i].s) } // 按照s降序排列 sort.Slice(arr, func(i, j int) bool { if arr[i].s > arr[j].s { return true }else if arr[i].s == arr[j].s && arr[i].v > arr[j].v { return true } return false }) heap, last := make([]Soldier, arr[0].s), 1 ans, total := arr[0].v, arr[0].v heap[0] = arr[0] for i := 1; i < n; i++ { for last >= arr[i].s && heap[0].v < arr[i].v{ total -= heap[0].v heap[0] = heap[last - 1] siftDown(heap, last) last -- } if last < arr[i].s { heap[last] = arr[i] total += heap[last].v siftUp(heap, last) last ++ } if total > ans { ans = total } } Fprintln(out, ans) } func main() { NC50439(os.Stdin, os.Stdout) }