参考博客:https://www.luogu.com.cn/blog/Sooke/solution-p5017
//把各个点映射到数轴上
//然后
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 4000105;
int n, m, t, ti, ans = 1e9;
int cnt[N], sum[N], q[N], f[N];
double getSlope(int u, int v)
{
return (double)(f[v] + sum[v] - f[u] - sum[u]) / (cnt[u] == cnt[v] ? 1e-9 : cnt[v] - cnt[u]);
}
int main()
{
cin >> n >> m;
for(int i=1; i <= n; i++)
{
cin >> ti;
ti ++;
t = max(t, ti);
//人数++
cnt[ti] ++;
//对应到数轴上
sum[ti] += ti;
}
for(int i = 1; i < t + m; i ++)
{
cnt[i] += cnt[i - 1]; // 前缀和.
sum[i] += sum[i - 1];
}
int hh = 0, tt = 0;
for(int i = 1; i <= t + m; i++)
{
if(i > m)
{
while(hh < tt && getSlope(q[tt - 1], q[tt]) >= getSlope(q[tt], i - m))
tt --;
q[++ tt] = i - m; // 把可能成为最优解的推入队列.
}
while(hh < tt && getSlope(q[hh], q[hh + 1]) <= i)
hh ++; // 把不可能成为最优解的弹出队列.
f[i] = cnt[i] * i - sum[i]; // 特判边界情况.
if(hh <= tt)
f[i] =min(f[i], f[q[hh]] + (cnt[i] - cnt[q[hh]]) * i - (sum[i] - sum[q[hh]])); // 斜率优化转移.
}
for(int i = t; i < t + m; i++)
ans = min(ans, f[i]);
cout << ans << endl;
return 0;
}