BZOJ1010 玩具装箱toy

斜率优化dp。首先比较容易想到:

         

但是很不幸,由上式的可以看出这实际上要用到两层循环,而数据量为50000,如果这样做,肯定超时,这时候需要斜率优化了。

       如果递推式能变成,且单调,则可使用斜率优化。

  我们将式变形,令,则

    

          

由此判断可以使用斜率优化。

       关键的来了:

       如果我们认为的两个方案且的方案的方案好则:

    $dp[j]+(g[i]-g[j]-c)^2\leq dp[k]+(g[i]-g[k]-c)^2$

    $\frac{dp[j]+g[j]^2+2*g[j]*c-dp[k]-g[k]^2-2*g[k]*c}{g[j]-g[k]} > g[i]$

  然后将,可以看出这个分式实际上就表示斜率,由这个斜率我们可以得出,如果的方案的方案好,则必须满足式,所以我们现在只需要将最有方案放在一个队列里,然后维护这个队列就行了,也就是凸包的维护。

    

  我讲下我个人当时最难理解的地方,为什么最优解在凸包上。

                            

  如上图所示,不在凸包上有两种情况,一种是F,一种是D。如果F在队列里,很明显,斜率为负的,不符合,排除,如果D在队列里,CD的斜率小于CB斜率,可得CB最优,所以排除D。

  然后是凸包的维护方法。

首先是取。如果时,是由转移而来,因为如果不满足不等式,说明方案并不是最有的,直接剔除,如果满足不等式,则当前这个点就是最优解,因为由函数知道,优于

  然后是加。如果$slope(q[back],i)<slope(q[back-1],q[back])$,也就是加入变成了凹的,我们需要将出列,直到不等式不成立,再将加到队列中。

code:

#define frp

#include<bits/stdc++.h>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <cstring>
#include <string>
#include <string.h>

using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f;
const ll inf = 0x7fffff;
const int maxn = 1e6;
const int MAXN = 1100000 + 10;
const int MOD = 1e9 + 7;

ll dp[maxn],sum[maxn],q[maxn];
int c,l;

double slope(int i,int j){
    return (dp[i]+sum[i]*sum[i]+2*sum[i]*c-dp[j]-sum[j]*sum[j]-2*sum[j]*c)/(2.0*(sum[i]-sum[j]));
}

void solve() {
    int n;
    cin>>n>>l;
    c=l+1;
    for(int i=1;i<n+1;i++){
        ll tmp;
        cin>>tmp;
        sum[i]=sum[i-1]+tmp;
    }
    for(ll i=1;i<n+1;i++)sum[i]+=i;
    int front=1,back=1;
    q[back]=0;
    for(int i=1;i<n+1;i++){
        while(front<back&&slope(q[front],q[front+1])<=sum[i])front++;
        int w=q[front];
        dp[i]=dp[w]+(sum[i]-sum[w]-c)*(sum[i]-sum[w]-c);
        while(front<back&&slope(q[back],i)<slope(q[back-1],q[back]))back--;
        q[++back]=i;
    }
    cout<<dp[n]<<endl;
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef frp
    freopen("D:\\coding\\c_coding\\in.txt", "r", stdin);
//    freopen("D:\\coding\\c_coding\\out.txt", "w", stdout);
#endif
    solve();
    return 0;
}

  

posted @ 2018-10-24 17:09  visualVK  阅读(176)  评论(0编辑  收藏  举报