• BZOJ1010 玩具装箱toy


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

             

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

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

      我们将式变形,令,则

        

              

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

           关键的来了:

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

        $dp[j]+(g[i]-g[j]-c)^2leq 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;
    }
    

      

  • 相关阅读:
    快速排序
    优先队列
    堆排序
    树、二叉树基础
    分治法
    递归算法详细分析
    算法基础
    Linux文件系统详解
    fs/ext2/inode.c相关函数注释
    块设备的读流程分析
  • 原文地址:https://www.cnblogs.com/visualVK/p/9844578.html
Copyright © 2020-2023  润新知