BZOJ 4518 征途

Posted on 2016-12-27 16:33  ziliuziliu  阅读(118)  评论(0编辑  收藏  举报

斜率优化。又是变量名打错看了老半天。

把方差式子展开一下就好了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 3050
#define inf 0x7f7f7f7f7f7f7f7fLL
using namespace std;
long long n,m,a[maxn],sum[maxn],dp[maxn][maxn],rk[maxn],l,r,q[maxn];
double k(long long x,long long y)
{
    if (sum[x]==sum[y]) return inf;
    return (double)(rk[x]-rk[y])/(sum[x]-sum[y]);
}
void k_dp()
{
    for (long long i=1;i<=n;i++) dp[1][i]=sum[i]*sum[i];
    for (long long i=2;i<=m;i++)
    {
        l=r=1;q[l]=i-1;
        for (long long j=i-1;j<=n;j++) rk[j]=dp[i-1][j]+sum[j]*sum[j];
        for (long long j=i;j<=n;j++)
        {
            while ((r-l) && (k(q[r-1],q[r])>k(q[r],j))) r--;
            q[++r]=j;
            while ((r-l) && (k(q[l],q[l+1])<=2*sum[j])) l++;
            dp[i][j]=dp[i-1][q[l]]+(sum[j]-sum[q[l]])*(sum[j]-sum[q[l]]);
        }
    }
}
long long get_ans()
{
    return dp[m][n]*m-sum[n]*sum[n];
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for (long long i=1;i<=n;i++) {scanf("%lld",&a[i]);sum[i]=sum[i-1]+a[i];}
    k_dp();
    printf("%lld\n",get_ans());
    return 0;
}