BZOJ-1010-斜率优化-决策单调性

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题目:传送门

 题目描述及样例在最下面。

思路:

 考虑斜率优化,决策单调性。

ar[i]为(前缀i的长度和+i)
f[i]为到i所花费的钱
 f[i]=min(f[j-1]+(ar[i]-ar[j-1]-L-1)^2);
=> f[i]=min(f[j]+(ar[i]-ar[j]-L-1)^2);
令c=L+1

第一步:

 假设j < k < i,如果点 i 在点 k 的决策优于在点 j 的决策,即

f[k] + (ar[i]-ar[k]-c)^2 <= f[j] + (ar[i]-ar[j]-c)^2

=> f[k] - 2*ar[i]* (ar[k]+c) + (ar[k]+c)^2 <= f[j] - 2*ar[i]* (ar[j]+c) + (ar[j]+c)^2

=> f[k] - f[j] + (ar[k]+c)^2 - (ar[j]+c)^2 <= 2*ar[i]* (ar[k]-ar[j])

=> (f[k] - f[j] + (ar[k]+c)^2 - (ar[j]+c)^2)/2* (ar[k]-ar[j]) <= ar[i]

 将上述式子定义为j和k的斜率。注意:j < k。
 如果在点 k 处决策优于在点 j 处决策,则有:斜率(j, k) <= ar[i]

(f[k] - f[j] + (ar[k]+c)^2 - (ar[j]+c)^2)/2* (ar[k]-ar[j]) <= ar[i]

第二步:

 使用单调队列来维护这一关系。使得队列中的斜率单调上升。
这里写图片描述
 head为队首,tail为队尾。新加入的点为i。

 斜率(head,head+1) <= ar[i],则将head点pop出去。
 因为head+1点除的决策优于head点。

 如果斜率(tail, i) < 斜率(tail-1,tail),则将tail点pop出去。
 如果不pop出去,无法维持队列中元素的决策单调性(单调上升)。

AC代码:

#include<bits/stdc++.h>
#define fang(a) (a)*(a)
using namespace std;
typedef long long LL;
const int N = 50000+5;
int n,k,head,tail;
int stak[N];
LL ar[N],f[N];
/*
  f[k] + (ar[i]-ar[k]-c)^2 <= f[j] + (ar[i]-ar[j]-c)^2
=> f[k] - 2*ar[i]*(ar[k]+c) + (ar[k]+c)^2 <= f[j] - 2*ar[i]*(ar[j]+c) + (ar[j]+c)^2
=> f[k] - f[j] + (ar[k]+c)^2 - (ar[j]+c)^2 <= 2*ar[i]*(ar[k]-ar[j])
=> (f[k] - f[j] + (ar[k]+c)^2 - (ar[j]+c)^2)/2*(ar[k]-ar[j]) <= ar[i]
*/
double fx(int x,int y){
    return (f[y]-f[x]+fang(ar[y]+k+1)-fang(ar[x]+k+1))/(2*(ar[y]-ar[x]));
}
int main(){
    while(~scanf("%d%d",&n,&k)){
        ar[0]=0;head=tail=1;
        memset(stak,0,sizeof(stak));
        memset(f,0,sizeof(f));
        for(int i=1,x;i<=n;++i){
            scanf("%d",&x);
            ar[i]=ar[i-1]+x;
        }
        for(int i=1;i<=n;++i)ar[i]+=i;
        for(int i=1;i<=n;++i){
            while(head<tail&&fx(stak[head],stak[head+1])<=ar[i])head++;
            f[i]=f[stak[head]]+fang(ar[i]-ar[stak[head]]-k-1);
            while(head<tail&&fx(stak[tail-1],stak[tail])>fx(stak[tail],i))tail--;
            stak[++tail]=i;
        }
        printf("%lld\n",f[n] );
    }
    return 0;
}


BZOJ1010: Description

  P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压
缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1…N的N件玩具,第i件玩具经过
压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容
器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一
个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关,根据教授研究,
如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容
器,甚至超过L。但他希望费用最小.

扫描二维码关注公众号,回复: 1576889 查看本文章

Input

  第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7

Output

  输出最小费用

Sample Input

5 4

3

4

2

1

4

Sample Output

1

猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/80668515
今日推荐