这是个很明显的DP题目,排序之后容易想到DP方程为dp【i】 = dp【j】 + w【j + 1,i】
然而4*10^5次方明显TLE,必须得优化,因为是一维的状态表示,所以四边形优化应该不可行(个人做题太少了,没见过一维的四边形优化)
另外w函数和j有关,所以单调队列不可行了,只能往斜率优化想了,斜率优化证明还算容易吧,证出来之后就相当于模板了
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x7ffffffffffLL
#define LL __int64
using namespace std;
const int maxn = 400005;
LL moo[maxn],q[maxn];
LL dp[maxn],sum[maxn];
LL n,m;
LL get_y(LL i,LL j){
return (dp[i] + (i) * moo[i + 1] - sum[i] ) - (dp[j] + (j) * moo[j + 1] - sum[j]);
}
LL get_x(LL i,LL j){
return moo[i + 1] - moo[j + 1];
}
LL get_dp(LL j,LL t)
{
return dp[j] + sum[t] - sum[j] - (t - j) * moo[j + 1];
}
void solve();
int main()
{
int i;
while(scanf("%I64d%I64d",&n,&m) != EOF){
for(i = 1;i <= n;i ++)
scanf("%I64d",&moo[i]);
sort(moo + 1,moo + 1 + n);
/* for(i = 1;i <= n;i ++)
printf("%d ",moo[i]);
putchar('\n');*/
for(i = 1;i <= n;i ++)
sum[i] = sum[i - 1] + moo[i];
memset(dp,0,sizeof(dp));
solve();
/* for(i = 1;i <= n;i ++)
printf("I:%d DP:%I64d get:%I64d\n",i,dp[i],get_dp(0,i));*/
}
return 0;
}
void solve()
{
LL head,tail,i;
head = tail = 0;
for(i = 1;i < m; i++)
dp[i] = INF;
q[0] = 0;
for(i = m;i <= n;i ++){
LL p = i - m;
while(head < tail){
LL x1 = get_x(q[tail - 1],q[tail]);
LL y1 = get_y(q[tail - 1],q[tail]);
LL x2 = get_x(q[tail],p);
LL y2 = get_y(q[tail],p);
if(y1 * x2 >= y2 * x1) tail --;
else break;
}
q[++ tail] = p;
while(head < tail){
LL a = get_dp(q[head],i);
LL b = get_dp(q[head + 1],i);
if(a > b) head ++;
else break;
}
// if(i == 7) printf("HEAD:%I64d\n",q[head]);
dp[i] = get_dp(q[head],i);
}
printf("%I64d\n",dp[n]);
}