小红闯关
思路
题目在说什么?有 个关卡,必须按顺序通过。通过第
关需要
时间。每通过
个关卡(无论是正常通过还是用道具跳过),就获得一个跳关道具。跳关道具可以在任意关卡使用,使用后零时间通过该关。问通过所有关卡的最少时间。
那怎么想这道题呢?
关键观察
首先,无论怎么选择跳哪些关卡,所有 关都会被通过(要么花时间打,要么用道具跳)。所以第
关(1-indexed)通过后,累计通过了
关,已获得
个道具。
但道具在通过第 关之后才产生,所以在第
关之前,可用的道具数量是
。
于是问题转化为:从 个关卡中选出一个子集
来跳过,最大化
(即省下的时间),同时对所有
都满足
。
答案就是 。
贪心策略
用一个小根堆维护当前选中要跳过的关卡的耗时。从左到右扫描每个关卡 :
- 如果当前选中的跳过数 <
(即还有空余道具),直接把
加入堆。
- 如果已经选满了,但
比堆中最小值更大,就把最小的换出来,把
放进去——这样总省时更多。
这样保证了在每个前缀处,跳过的关卡数都不超过该前缀允许的道具数。
时间复杂度 ,空间复杂度
。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k;
scanf("%d%d", &n, &k);
vector<int> t(n);
long long totalSum = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &t[i]);
totalSum += t[i];
}
priority_queue<int, vector<int>, greater<int>> minHeap;
long long skippedSum = 0;
for (int i = 0; i < n; i++) {
int j = i + 1;
int capacity = (j - 1) / k;
if ((int)minHeap.size() < capacity) {
minHeap.push(t[i]);
skippedSum += t[i];
} else if (capacity > 0 && !minHeap.empty() && t[i] > minHeap.top()) {
skippedSum -= minHeap.top();
minHeap.pop();
minHeap.push(t[i]);
skippedSum += t[i];
}
}
printf("%lld\n", totalSum - skippedSum);
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int[] t = new int[n];
long totalSum = 0;
for (int i = 0; i < n; i++) {
t[i] = sc.nextInt();
totalSum += t[i];
}
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
long skippedSum = 0;
for (int i = 0; i < n; i++) {
int j = i + 1;
int capacity = (j - 1) / k;
if (minHeap.size() < capacity) {
minHeap.offer(t[i]);
skippedSum += t[i];
} else if (capacity > 0 && !minHeap.isEmpty() && t[i] > minHeap.peek()) {
skippedSum -= minHeap.poll();
minHeap.offer(t[i]);
skippedSum += t[i];
}
}
System.out.println(totalSum - skippedSum);
}
}
import sys
import heapq
input = sys.stdin.readline
n, k = map(int, input().split())
t = list(map(int, input().split()))
total_sum = sum(t)
min_heap = []
skipped_sum = 0
for i in range(n):
j = i + 1
capacity = (j - 1) // k
if len(min_heap) < capacity:
heapq.heappush(min_heap, t[i])
skipped_sum += t[i]
elif capacity > 0 and min_heap and t[i] > min_heap[0]:
skipped_sum -= heapq.heappop(min_heap)
heapq.heappush(min_heap, t[i])
skipped_sum += t[i]
print(total_sum - skipped_sum)
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
const lines = [];
rl.on('line', line => lines.push(line));
rl.on('close', () => {
const [n, k] = lines[0].split(' ').map(Number);
const t = lines[1].split(' ').map(Number);
let totalSum = 0;
for (let i = 0; i < n; i++) totalSum += t[i];
const heap = [];
const heapPush = (v) => {
heap.push(v);
let i = heap.length - 1;
while (i > 0) {
const p = (i - 1) >> 1;
if (heap[p] <= heap[i]) break;
[heap[p], heap[i]] = [heap[i], heap[p]];
i = p;
}
};
const heapPop = () => {
const top = heap[0];
const last = heap.pop();
if (heap.length > 0) {
heap[0] = last;
let i = 0;
while (true) {
let s = i;
const l = 2 * i + 1, r = 2 * i + 2;
if (l < heap.length && heap[l] < heap[s]) s = l;
if (r < heap.length && heap[r] < heap[s]) s = r;
if (s === i) break;
[heap[s], heap[i]] = [heap[i], heap[s]];
i = s;
}
}
return top;
};
let skippedSum = 0;
for (let i = 0; i < n; i++) {
const j = i + 1;
const capacity = Math.floor((j - 1) / k);
if (heap.length < capacity) {
heapPush(t[i]);
skippedSum += t[i];
} else if (capacity > 0 && heap.length > 0 && t[i] > heap[0]) {
skippedSum -= heapPop();
heapPush(t[i]);
skippedSum += t[i];
}
}
console.log(totalSum - skippedSum);
});



京公网安备 11010502036488号