还是要先排序
设sum[i]为兴趣值的前缀和
设DP[i]为目前为止最优的分组
则DP[i]=min(DP[j]+sum[i]-sum[j]-a[j]*(i-j+1))
设k<j&&j决策更优
DP[j]+sum[i]-sum[j]-a[j]*(i-j+1)<DP[k]+sum[i]-sum[k]-a[k]*(i-k+1)
==>DP[j]-sum[j]-a[j]+a[j]*j-(DP[k]-sum[k]-a[k]+a[k]*k)<(a[j]-a[k])*i
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int SIZEN=400050;
const LL INF=1ll<<50;
LL dp[SIZEN];
LL a[SIZEN],s[SIZEN];
int q[SIZEN];
int head,tail;
LL read(){
char ch=' ';
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
LL ans=0,flag=1;
if(ch=='-'){flag=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
ans*=10;
ans+=ch-'0';
ch=getchar();
}
return ans*flag;
}
LL getup(int k,int j){
return dp[j]-s[j]+a[j+1]*j-(dp[k]-s[k]+a[k+1]*k);
}
LL getdown(int k,int j){
return a[j+1]-a[k+1];
}
LL getval(int i,int j){
return dp[j]+s[i]-s[j]-a[j+1]*(i-j);
}
void solve(int n,int m){
for(int i=1;i<=n;i++) a[i]=read();
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
dp[0]=a[0]=s[0]=0;
head=tail=0;
q[tail++]=0;
for(int i=m,j=1;i<=n;i++,j++){
while(head+1<tail){
LL dy=getup(q[head],q[head+1]);
LL dx=getdown(q[head],q[head+1]);
if(dy<=i*dx) head++;
else break;
}
dp[i]=getval(i,q[head]);
if(j<m) continue;
while(head+1<tail){
LL dy1=getup(q[tail-2],q[tail-1]);
LL dx1=getdown(q[tail-2],q[tail-1]);
LL dy2=getup(q[tail-1],j);
LL dx2=getdown(q[tail-1],j);
if(dy1*dx2>=dy2*dx1) tail--;
else break;
}
q[tail++]=j;
}
printf("%I64d\n",dp[n]);
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
solve(n,m);
}