JZOJsenior3479.【NOIP2013模拟联考9】工作安排(work)

来源:互联网 发布:2015年水产品出口数据 编辑:程序博客网 时间:2024/05/21 17:42

problem

Description

众所周知Kelukin是一名宇宙级土豪,他公司的生意自然是相当的好。

现在他手上有n份工作要完成,每一份工作有一个土豪指标Ak。由于这些工作数量太多,Kelukin又懒,所以他无法一个人完成,他需要雇用很多工人来帮忙。可是Kelukin十分小气,经常克扣工资,因此没有多少人愿意帮他。而愿意帮他的那些工人各个都是奇葩,而且他们非常精明,按工作量收费,小于k份的工作量他们是不会去做的,而他们完成一次工作要额外收C元。一个工人最多做一次工作。

Kelukin表示那些工作之间有很多是类似的,完成了第一份第二份能很快扫完,因此他这么规定一个工人的报酬:若工人所做的工作的土豪指标为(T1,T2,T3,T4……,Tm),则他的报酬为C+(maxTi-minTi)^2,1<=i<=m,m>=k。

作为Kelukin的贴身秘书,你有义务告诉他为了完成这n份工作最少要花多少钱。当然,Kelukin非常的小气,他是不会给你工资的。

Input

第一行三个正整数n、k、C(1≤k≤n≤10^6,0≤C≤10^9),之间用一个空格隔开。

第二行为n个正整数,描述n份工作的土豪指标(0<Ak≤10^9),之间用一个空格隔开。

Output

一行仅一个整数,表示Kelukin最少需要支付的工资(保证答案不大于10^17)。

Sample Input

2 1 1

2 4

Sample Output

2

【样例说明】

如果分给一个工人做,收费为 1 + (4 – 2) ^2 = 5。

如果分给两个工人作,收费为 1 + 1 = 2。

所以最小收费为2。

Data Constraint

对于50%的测试数据中保证有N≤1000。

对于70%的测试数据中保证有N≤50000。

对于100%的测试数据中保证有N≤1000000。


analysis

一道斜率DP题目……还很™裸……

50%数据

首先我们会很easy地搞出一个DP方程,设f[i]表示到了第i位的工资最小值,有:

f[i]=mini[k,n],j[1,ik+1](f[i],f[j1]+(a[i]a[j])2+c)

不要问我怎么推出来的这个都不推您不要学OI了呗
照着这个打,RE&TLE50


100%数据

请先点开下面的链接

斜率DP入门必看blog:https://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html

看完了吗?
你会发现这篇blog里的方程和上面那个基本一模一样
用我自己简单的话来看一看,这里DP斜率优化的思想吧!


  • 首先这是最原始的DP方程

  • f[i]=mini[k,n],j[1,ik+1](f[i],f[j1]+(a[i]a[j])2+c)

  • 假设k<j<ij决策比k决策则有

  • f[j1]+(a[i]a[j])2+c<f[k1]+(a[i]a[k])2+c
  • 给上面那个不等式移项一下(请一定要手推一下),得到

  • (f[j1]+a[j]2)(f[k1]+a[k]2)2a[j]2a[k]<a[i]
    2a[j]只与j有关,所以我们用yjxj来代替k同理,不等式变为

  • yjykxjxk<a[i]
    决策比k决策,若此不等式成立,就说明j决策确实比k决策

  • 为了更方便地探究,我们先设slope(α,β)=yαyβxαxβ

  • 现在我们还是设k<j<i,那么最关键的优化就是:

    slope(i,j)<slope(j,k),那么j一定不是最优决策点

  • 我们假设slope(i,j)<sum[i],那么i决策比j决策优,排除j决策点

  • 如果slope(i,j)>=a[i],那么j决策此时比i决策要优,但是同时g[j,k]>g[i,j]>a[i],这说明还有k决策比j决策更优,同样排除j决策点

  • 所以斜率优化的核心就是去掉决策肯定更劣的点


  • 如何求解呢?单调队列维护!

  • 由于我们是要求斜率的单调性,那么单调队列就一定呈单调递增或递减

  • 每次新加入一个决策点时,从队列尾部删除不符合要求的决策点,并把新决策点放在队尾

  • 删除:若slope(queue[tail],queue[tail1])<slope(queue[tail1],queue[tail2])则队尾较劣,删除队尾

  • 求解i号位时,若slope(queue[head+1],queue[head])<a[i]

大功告成
初始化不要忘记f[k]k[1,k)=INF


code

#include<stdio.h>#include<cstring>#include<algorithm>#define sqr(x) ((x)*(x))#define MAXN 1000001#define INF 1000000000000000007using namespace std;long long a[MAXN],f[MAXN];int queue[MAXN],head,tail;int n,k,c;double slope(int x,int y) {    return ((f[y-1]+sqr(a[y]))-(f[x-1]+sqr(a[x])))/(2.0*(a[y]-a[x]));}void insert(int x){    while (head<=tail && a[queue[tail]]==a[x])     {        if (f[x-1]<f[queue[tail]-1])tail--;        else return;    }    while (head<tail && slope(queue[tail-1],queue[tail])>slope(queue[tail],x))tail--;    queue[++tail]=x;}int main() {    freopen("work.in","r",stdin);    freopen("work.out","w",stdout);    scanf("%d%d%d",&n,&k,&c);    for (int i=1;i<=n;i++)    {        scanf("%d",&a[i]);    }    sort(a+1,a+n+1);    for (int i=1;i<k;i++)f[i]=INF;    head=1,tail=0;    for (int i=k;i<=n;i++)     {        int x=i-k+1;        insert(x);        while (head<tail && slope(queue[head],queue[(head+1)])<a[i])head++;        f[i]=f[queue[head]-1]+sqr(a[i]-a[queue[head]])+c;    }    printf("%lld\n",f[n]);    return 0;}