[SDOI2016]征途

题目描述

Pine开始了从S地到T地的征途。

从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站。

Pine计划用m天到达T地。除第m天外,每一天晚上Pine都必须在休息站过夜。所以,一段路必须在同一天中走完。

Pine希望每一天走的路长度尽可能相近,所以他希望每一天走的路的长度的方差尽可能小。

帮助Pine求出最小方差是多少。

设方差是v,可以证明,v\times m^2v×m2是一个整数。为了避免精度误差,输出结果时输出v\times m^2v×m2。

 毒瘤sdoi出的毒瘤题。

先是卡空间,又是卡时间,最后做了3个点才做完。

正经事:

1.答案是( sigma(m*xi - sn)^2 ) / m。

2.普通dp一定过不了,由于其满足斜率优化以及决策单调,我们可以用斜率优化dp来做。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 3050
ll n,m;
ll s[N],f[N][N];
int q[N][N],h[N],t[N];
ll x(int i)
{
    return 1ll*m*s[i]+s[n];
}
ll k(int i)
{
    return 2ll*m*s[i];
}
ll y(int i,ll d)
{
    return f[i][d]+x(i)*x(i);
}
ll b(int i)
{
    return m*m*s[i]*s[i];
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld",&s[i]),s[i]+=s[i-1];
    memset(f,0x3f,sizeof(f));
    f[0][0]=0;
    for(int d=0;d<m;d++)
    {
        for(int i=max(d-1,0);i<=n;i++)
        {
            while(h[d]<t[d]&&(y(q[h[d]+1][d],d)-y(q[h[d]][d],d)<=k(i)*(x(q[h[d]+1][d])-x(q[h[d]][d]))))h[d]++;
            f[i][d+1]=y(q[h[d]][d],d)-k(i)*x(q[h[d]][d])+b(i);
            while(h[d+1]<t[d+1]&&((y(i,d+1)-y(q[t[d+1]][d+1],d+1))*(x(q[t[d+1]][d+1])-x(q[t[d+1]-1][d+1]))<=(y(q[t[d+1]][d+1],d+1)-y(q[t[d+1]-1][d+1],d+1))*(x(i)-x(q[t[d+1]][d+1]))))t[d+1]--;
            q[++t[d+1]][d+1] = i;
        }
    }
    printf("%lld\n",f[n][m]/m);
    return 0;
}

 

posted @ 2018-09-12 01:51  LiGuanlin  阅读(192)  评论(0编辑  收藏  举报