/*
我的想法是从最后一个获得道具的位置开始向前,看在每一个位置上获得的道具最多可以减少多少时间,因为后面关卡的道具不能用在获得结点之前,所以说要从最后一个获得道具的位置进行判断,去掉跳过的关卡的前提下进行前面获得道具最大跳过时间的判断
具体的思路是1、计算出不用跳关的总用时sum,并设置变量save_time
2、首先维护一个大顶堆,初始为空,然后从后向前扫描数组,每次扫描时先检测是否获得道具,即为(i + 1)/k == 0,若获得道具则使得 save_time + 大顶堆堆顶的值,并把堆顶移除,扫描后将关卡加入大顶堆
3、扫描结束后得到save_time,用sum - save_time即可得到所需的最小时间
*/
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 100000000
/*手动实现一个大顶堆*/
//定义大顶堆结构体
struct maxheap{
long long heap[MaxSize];
int size;
};
//1、定义初始化函数
void Init(struct maxheap *h){
h->size = 0;
}
//2、交换元素值
void swap(long long *a, long long *b){
long long tmp = *a;
*a = *b;
*b = tmp;
}
//3、实现下沉操作
void sink(struct maxheap *h, int i){
while(1){
int left = 2 * i + 1;
int right = 2 * i + 2;
int largest = i;
if(left < h->size && h->heap[left] > h->heap[largest]){
largest = left;
}
if(right < h->size && h->heap[right] > h->heap[largest]){
largest = right;
}
if(largest == i){
break;
}
else{
swap(&h->heap[i],&h->heap[largest]);
i = largest;
}
}
}
//4、实现上浮操作
void Float(struct maxheap *h, int i){
while(i >= 0){
int parent = (i - 1) / 2;
if(h->heap[i] <= h->heap[parent]){
break;
}
else{
swap(&h->heap[i], &h->heap[parent]);
i = parent;
}
}
}
//5、插入操作
void push(struct maxheap *h, long long n){
if(h->size >= MaxSize){
return;
}
else{
h->heap[h->size] = n;
Float(h, h->size);
h->size ++;
}
}
//6、弹出操作
int pop(struct maxheap *h, long long *n){
if(h->size <= 0){
return 0;
}
else{
*n = h->heap[0];
swap(&h->heap[h->size - 1],&h->heap[0]);
h->size--;
sink(h, 0);
return 1;
}
}
//取堆顶元素
long long Top(struct maxheap h){
if(h.size <= 0){
return -1;
}
else{
return h.heap[0];
}
}
//主函数
int main() {
//读取数据
long long n, k;
scanf("%lld %lld\n", &n, &k);
long long *a = (long long *)malloc(sizeof(long long) * n);
if(a == NULL){
printf("Failed Malloc!\n");
return -1;
}
long long sum = 0;//res记录最终的结果,初始化为0
for(long long i = 0; i < n; i++){
scanf("%lld", a + i);
sum += *(a + i);//res先取所有关卡的时间和
}
long long save_time = 0;//节省的时间
//建立大顶堆
struct maxheap h;
Init(&h);
//从最后一个元素开始遍历数组
for(int i = n - 1; i >= 0; i--){
if((i + 1) % k == 0){//是获得道具的关卡
long long tmp;
if(pop(&h, &tmp)){
save_time += tmp;
}
}
push(&h,a[i]);
}
printf("%lld\n",sum - save_time);//打印结果
//释放空间
free(a);
return 0;
}