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 位的工资最小值,有:
不要问我怎么推出来的这个都不推您不要学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,i−k+1](f[i],f[j−1]+(a[i]−a[j])2+c)
假设 k<j<i 且 j 决策比
k 决策优则有-
f[j−1]+(a[i]−a[j])2+c<f[k−1]+(a[i]−a[k])2+c
给上面那个不等式移项一下(请一定要手推一下),得到
- (f[j−1]+a[j]2)−(f[k−1]+a[k]2)2a[j]−2a[k]<a[i]
由于 f[j−1]+a[j]2 和 2a[j] 只与 j 有关,所以我们用
yj 和 xj 来代替, k 同理,不等式变为yj−ykxj−xk<a[i] 这是什么东西?斜率!
我们前面假设 j 决策比
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[tail−1])<slope(queue[tail−1],queue[tail−2]) 则队尾较劣,删除队尾求解 i 号位时,若
slope(queue[head+1],queue[head])<a[i] ,则队头较劣,删除队头- 最后
f[i]=f[queue[head]−1]+(a[i]−a[queue[head]])2+c
大功告成
初始化不要忘记
f[k]k∈[1,k)=INF
!
code
#include<stdio.h>
#include<cstring>
#include<algorithm>
#define sqr(x) ((x)*(x))
#define MAXN 1000001
#define INF 1000000000000000007
using 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;
}

1111

被折叠的 条评论
为什么被折叠?



