Pine开始了从S地到T地的征途。
从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站。
Pine计划用m天到达T地。除第m天外,每一天晚上Pine都必须在休息站过夜。所以,一段路必须在同一天中走完。
Pine希望每一天走的路长度尽可能相近,所以他希望每一天走的路的长度的方差尽可能小。
帮助Pine求出最小方差是多少。
设方差是v,可以证明,v×m2是一个整数。为了避免精度误差,输出结果时输出v×m2。
Input
第一行两个数 n、m。
第二行 n 个数,表示 n 段路的长度
Output
一个数,最小方差乘以 m^2 后的值
Sample Input
5 2
1 2 5 8 6
Sample Output
36
Hint
1≤n≤3000,保证从 S 到 T 的总路程不超过 30000
dp截距优化板题。。。
#include<bits/stdc++.h>
using namespace std;
#define N 50005
int n, l;
int head, tail, q[N];
long long sum[N], f[N];
inline long long getans(int i, int j)
{
return f[j]+sum[j]*sum[j]-2ll*(sum[i]-l)*sum[j]+(sum[i]-l)*(sum[i]-l);
}
inline bool cmp(int i, int j, int k)
{
return (f[j]+sum[j]*sum[j]-f[i]-sum[i]*sum[i])*(sum[k]-sum[j]) >= (f[k]+sum[k]*sum[k]-f[j]-sum[j]*sum[j])*(sum[j]-sum[i]);
}
void solve()
{
head = tail = 1;
q[tail++] = f[0] = 0;
for (int i = 1; i <= n; i++)
{
//遍历凸包
while (head+1 < tail && getans(i, q[head]) >= getans(i, q[head+1]))
head++;
f[i] = getans(i, q[head]);
//比较斜率维护凸包
while (head+1 < tail && cmp(q[tail-2], q[tail-1], i))
tail--;
q[tail++] = i;
}
}
int main()
{
int x;
scanf("%d%d", &n, &l);
for (int i = 1; i <= n; i++)
{
scanf("%d", &x);
sum[i] = sum[i-1] + x+1;
}
++l;
solve();
printf("%lld\n", f[n]);
return 0;
}