题目
思路
我们先按从小到大排序,显然没错,又是显然答案的方案是连续的
设
d
p
i
dp_i
dpi为前i个的最优解。
dp方程:
d
p
i
=
m
i
n
(
d
p
j
+
s
i
−
s
j
−
a
j
+
1
∗
(
i
−
j
)
)
,
1
<
=
j
<
=
i
−
t
+
1
dp_i=min(dp_j+s_i-s_j-a_{j+1}*(i-j)),1<=j<=i-t+1
dpi=min(dpj+si−sj−aj+1∗(i−j)),1<=j<=i−t+1
因为
∗
(
i
−
j
)
*(i-j)
∗(i−j)我们不能单调队列优化,所以我们考虑斜率优化。
设对i来说,从k断开比j优,则有:
d
p
j
−
d
p
k
+
s
k
−
s
j
+
j
∗
a
j
+
1
−
k
∗
a
k
+
1
<
=
i
∗
(
a
j
+
1
−
a
k
+
1
)
dp_j-dp_k+s_k-s_j+j*a_{j+1}-k*a_{k+1} <= i*(a_{j+1}-a_{k+1})
dpj−dpk+sk−sj+j∗aj+1−k∗ak+1<=i∗(aj+1−ak+1)
然后就是喜闻乐见的代码了
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<queue>
#include<deque>
#define int long long
using namespace std;
int n,t,a[400001],s[400001],f[400001],u[400001],l,r,i,j;
int y(int x,int y)
{
return f[x]-s[x]+x*a[x+1]-(f[y]-s[y]+y*a[y+1]);
}
int x(int x,int y)
{
return a[x+1]-a[y+1];
}
int dp(int x,int y)
{
return f[y]+(s[x]-s[y])-a[y+1]*(x-y);
}
signed main()
{
while (cin>>n>>t)
{
for (i=1;i<=n;i++) cin>>a[i];
memset(f,0,sizeof(f));
l=r=0;
u[r++]=0;
sort(a+1,a+n+1);
for (i=1;i<=n;i++) s[i]=s[i-1]+a[i];
for (i=1;i<=n;i++)
{
while (l+1<r&&y(u[l+1],u[l])<=i*x(u[l+1],u[l])) l++;
f[i]=dp(i,u[l]);
j=i-t+1;
if (j<t) continue;
while (l+1<r&&y(j,u[r-1])*x(u[r-1],u[r-2])<=y(u[r-1],u[r-2])*x(j,u[r-1])) r--;
u[r++]=j;
}
cout<<f[n]<<endl;
}
return 0;
}