import java.util.Scanner;
import java.util.PriorityQueue;
import java.util.Collections;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
//c#写法,垃圾牛客的c#只支持到.net4,只能以注释形式把代码放这儿
/*string[] inputs = Console.ReadLine().Split(' ');
int.TryParse(inputs[0], out int n);
int.TryParse(inputs[1], out int k);
List<int> TimeCostOfEachGames = Console.ReadLine().Split(' ').Select(int.Parse).ToList();
//c#的优先队列是一个最小堆,所以我们传入我们的自定义比较器,使它成为一个最大堆
PriorityQueue<long, long> pq = new PriorityQueue<long, long>(Comparer<long>.Create((a, b) => b.CompareTo(a)));
long totalCost = 0;
long savedTime = 0;
long maxTime = TimeCostOfEachGames.Sum();
if(k == 1)//如果每通过一关就能获得一个跳关道具,那么只需要通过一关,后面的每一关都可以直接跳过,最后总耗时就是第一关的耗时
{
totalCost = TimeCostOfEachGames[0];
}
else if(k >= n)//如果获得跳关道具所需的关卡数量大于等于总关卡数量
{
totalCost = maxTime;
}
else//如果获得跳关道具所需的关卡数量小于总关卡数量
{
//因为我们的目标是“最小化总时间”,所以每获得一个道具,都应该用它跳过当前所有未使用的关卡中最耗时的那个。
//所以,我们不需要在获得道具的那一刻就决定跳过哪个关卡,而是可以“先记下来”,等看到后面更大的关卡时再用。
//从后往前遍历
for (int i = n-1; i > 0; i++)
{
//看看遍历到当前关卡能不能获得跳关道具
if(i % k == 0)
{
pq.Enqueue(TimeCostOfEachGames[i], TimeCostOfEachGames[i]);//将当前关卡的耗时加入优先队列
savedTime += pq.Dequeue();//将i到n-1之间最消耗时间的关卡的耗时加入savedTime,表示当前获得的跳关道具可以跳过的耗时
}
else
{
pq.Enqueue(TimeCostOfEachGames[i], TimeCostOfEachGames[i]);//将当前关卡的耗时加入优先队列
}
}
}
totalCost = maxTime - savedTime;
Console.WriteLine(totalCost); */
//java代码
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
long[] a = new long[n];
long totalTime = 0;
for (int i = 0; i < n; i++) {
a[i] = sc.nextLong();
totalTime += a[i];
}
// Java的PriorityQueue默认是最小堆,需要提供比较器实现最大堆
PriorityQueue<Long> pq = new PriorityQueue<>(Collections.reverseOrder());
long savedTime = 0;
// 从后往前遍历
for (int i = n - 1; i >= 0; i--) {
// 检查在通过此关后是否获得道具
if ((i + 1) % k == 0 && !pq.isEmpty()) {
// 用它跳过未来(i+1 到 n-1)最耗时的关卡
savedTime += pq.poll();
}
// 将当前关卡加入“未来”的候选池
pq.add(a[i]);
}
System.out.println(totalTime - savedTime);
}
}