第一行输入两个整数
代表关卡数量和获得跳关道具的条件。
第二行输入
个整数
代表通过每个关卡需要消耗的时间。
在一行上输出一个整数,表示小红通过这
个关卡所需的最少时间。
3 2 1 3 2
4
小红通过第二个关卡后获得跳关道具,此时消耗
单位时间;在第三个关卡使用跳关道具,不再消耗时间。
6 2 1 1 4 5 1 4
7
小红通过第二个关卡后获得第一个跳关道具;
在第四个关卡使用第一个跳关道具后得到第二个跳关道具;
在第六个关卡使用第二个跳关道具。
5 1 2 4 5 1 3
2
通过第一关后,后面的关卡都可以使用跳关道具。跳关也算一次成功的闯关。
贪心 + 最大堆
由题可知,每闯过k个关卡,就能获得一个跳关道具。
因此,下标为k的倍数的关卡都能获得一个跳关道具。
我们发现,这些范围有些部分是重叠的。对于重叠的部分,我们优先使用范围较小的跳关道具。
[jk, n-1]排除里面的最大值,然后[j-1k, n-1]就能够在剩余的范围内排除第二大的值。如果先使用[j-1k, n-1]排除了最大值,如果恰好第二大值在[j-1k, jk)这个范围内,[jk,n-1]的道具就白白浪费了,它只能排除[jk,n-1]中的最大值,该值在[j-1k,n-1]中可能第三大甚至第四大。
因此,为了充分利用跳关道具,我们需要先使用范围较小的跳关道具。
因此,我们从右往左遍历,当下标是k的倍数时,说明遇到了跳关道具,此时跳关时间加上之前遍历的元素的最大值。
然后继续遍历,遇到跳关道具,跳关时间就加上剩余元素的最大值。
最大值可以使用最大堆来进行记录。
代码实现如下:
import sys
import heapq
line = sys.stdin.readline().strip()
a = line.split()
n = int(a[0])
k = int(a[1])
line = sys.stdin.readline().strip()
nums = [int(num) for num in line.split()]
maxHeap = []
i = n - 1
maxJumpTime = 0
for i in range(n-1, -1, -1):
heapq.heappush(maxHeap, -nums[i])
if i != 0 and i % k == 0:
maxJumpTime += -heapq.heappop(maxHeap)
print(sum(nums) - maxJumpTime)
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int k = scanner.nextInt();
int[] times = new int[n];
for (int i = 0; i < n; i++) {
times[i] = scanner.nextInt();
}
// 计算能获得的跳关道具数量
int props = n / k;
// 如果没有道具,直接返回所有关卡时间总和
if (props == 0) {
long sum = 0;
for (int time : times) {
sum += time;
}
System.out.println(sum);
return;
}
// 使用小顶堆来保存我们要跳过的最大时间关卡
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
long totalSum = 0;
for (int i = 0; i < n; i++) {
totalSum += times[i];
// 记录当前已获得的道具数量 (到第i+1关为止)
int currentProps = i / k;
// 如果当前已获得的道具数量多于堆的大小,说明刚获得了新道具
if (currentProps > minHeap.size()) {
minHeap.add(times[i]);
}
// 如果已经获得了道具,且当前关卡时间比堆中最小的要大,则替换
else if (currentProps > 0 && times[i] > minHeap.peek()) {
minHeap.poll();
minHeap.add(times[i]);
}
}
// 计算需要减去的总时间(被跳过的关卡)
long skipSum = 0;
while (!minHeap.isEmpty()) {
skipSum += minHeap.poll();
}
System.out.println(totalSum - skipSum);
}
}
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int[] a = new int[n];
for(int i = 0;i < n;i ++ ) a[i] = sc.nextInt();
PriorityQueue<Integer> pq = new PriorityQueue<>(Comparator.reverseOrder());
long sum = 0;
for(int i = n - 1;i >= k;i -- ) {
pq.add(a[i]);
sum += a[i];
if(i % k == 0) {
sum -= pq.poll();
}
}
for(int i = k - 1;i >= 0;i -- ) sum += a[i];
System.out.println(sum);
}
} ans = sum(arr) m = (n - 1) // k if m == 0: print(ans) else: sort_arr = sorted(range(n), key=lambda i: -arr[i]) buckets = list(range(m+2)) def find(x): if buckets[x] == x: return x buckets[x] = find(buckets[x]) return buckets[x] def union(a, b): buckets[a] = find(buckets[b]) use_cnt = 0 for idx in sort_arr: bucket = idx // k if bucket < 1: continue tickt = find(bucket) if tickt >= 1: use_cnt += 1 ans -= arr[idx] union(tickt, tickt-1) if use_cnt == m: break print(ans)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n, k;
cin >> n >> k;
vector<int> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
// dp[i][j] 表示通过前i个关卡,剩余j个道具时的最小时间
const int INF = 1e18;
vector<vector<int>> dp(n + 1, vector<int>(n + 1, INF));
dp[0][0] = 0; // 初始状态:通过0个关卡,剩余0个道具,时间为0
for (int i = 0; i < n; ++i) {
for (int j = 0; j <= n; ++j) {
if (dp[i][j] == INF) continue; // 无效状态
// 情况1:使用一个道具跳过当前关卡i+1
if (j > 0) {
int new_j = j - 1;
// 检查使用道具后是否会获得新道具
int new_acquired = (i + 1) % k == 0 ? 1 : 0;
new_j += new_acquired;
if (new_j <= n && dp[i + 1][new_j] > dp[i][j]) {
dp[i + 1][new_j] = dp[i][j];
}
}
// 情况2:不使用道具,通过当前关卡i+1
int new_time = dp[i][j] + a[i];
// 检查通过后是否会获得新道具
int new_acquired = (i + 1) % k == 0 ? 1 : 0;
int new_j = j + new_acquired;
if (new_j <= n && dp[i + 1][new_j] > new_time) {
dp[i + 1][new_j] = new_time;
}
}
}
// 找出通过所有n个关卡后的最小时间
int min_time = INF;
for (int j = 0; j <= n; ++j) {
if (dp[n][j] < min_time) {
min_time = dp[n][j];
}
}
cout << min_time << endl;
return 0;
} #include <bits/stdc++.h>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
int main() {
LL n,k;
cin>>n>>k;
vector<LL>a(n);
LL res=0;
priority_queue<LL,vector<LL>,less<>>pq;
for(int i=0;i<n;i++){
cin>>a[i];
res+=a[i];
}
for(int i=n-1;i>=0;i--){
pq.push(a[i]);
if(i!=0 && i%k ==0){
int mx = pq.top();pq.pop();
res -= mx;
}
}
cout<<res;
}
// 64 位输出请用 printf("%lld") #include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int cmp(const void*a,const void*b){
return *(int*)a-*(int *)b;
}
int main() {
int a, b;
cin >> a >> b;
vector<int> arr;
int tmp = a;
while (tmp--) { // 注意 while 处理多个 case
int yl;
scanf("%d", &yl);
arr.push_back(yl);
}
if(b==1){
printf("%d",arr[0]);
return 0;
}
long long sum = 0;
for (int i = 0; i < b; ++i) {
sum += arr[i];
}
int left = a - a % b;
int right = a;
priority_queue<int> queue1;
for(int i=left;i<right;++i){
queue1.push(arr[i]);
}
if(!queue1.empty())
queue1.pop();
right = left;
left = right -b;
while(left>0){
for(int i=left;i<right;++i){
queue1.push(arr[i]);
}
queue1.pop();
right = left;
left = right -b;
}
while(!queue1.empty()){
sum += queue1.top();
queue1.pop();
}
printf("%lld", sum);
}
import sys for line in sys.stdin: a = line.split() n, k = int(a[0]), int(a[1]) num = list(map(int, input().split())) jump = n // k # 有多少次跳的机会 chance = [1] * (jump + 1) # 为每个元素添加索引信息,形成 (index, value) 元组 num_with_index = [(i, v) for i, v in enumerate(num)] # 按照值从大到小排序 maxnum = sorted(num_with_index, key=lambda x: x[1], reverse=True) jian = 0 for i, x in maxnum: j = i // k # 看在第几次能 jump for p in range(j, 0, -1): if chance[p] == 1: chance[p] = 0 jump -= 1 jian += x break if jump == 0: break print(sum([x[1] for x in maxnum]) - jian)有点超时了,15/20个用例通过,比一楼的答案通过更多