• 斜率dp


    HUD-3507
    Zero has an old printer that doesn't work well sometimes. As it is antique, he still like to use it to print articles. But it is too old to work for a long time and it will certainly wear and tear, so Zero use a cost to evaluate this degree.
    One day Zero want to print an article which has N words, and each word i has a cost Ci to be printed. Also, Zero know that print k words in one line will cost

    [(sum_{i=1}^kC_i)^2+M ]

    M is a const number.
    Now Zero want to know the minimum cost in order to arrange the article perfectly.

    Input
    There are many test cases. For each test case, There are two numbers N and M in the first line (0 ≤ n ≤ 500000, 0 ≤ M ≤ 1000). Then, there are N numbers in the next 2 to N + 1 lines. Input are terminated by EOF.

    Output
    A single number, meaning the mininum cost to print the article.

    Sample Input

    5 5
    5
    9
    5
    7
    5
    

    Sample Output

    230
    

    很容易推出:(dp[i]=min(dp[j]+(s[i]-s[j])^2+M)) 其中(j<i)
    这样的不加优化的裸dp是(O(n^2))的,5e5的数据肯定爆了
    假设(k<j<i)
    如果对于dp[i], j 比 k 优,有
    (dp[j]+(s[i]-s[j])^2+M)<dp[k]+(s[i]-s[k])^2+M))

    (dp[j]+s[j]^2-(dp[k]+s[j]^2)<2s[i](s[j]-s[k]))

    设$$g(k,j)=frac{dp[j]+s[j]2-(dp[k]+s[j]2)}{2(s[j]-s[k])}<s[i]$$
    也就是$$frac{y2-y1}{x2-x1}<k$$
    如果(g(k,j)<s[i]),说明j比k优,且s[i]是递增的,j永远比k优
    如果(g(a,b)>g(b,c)) b永远不是较优的:

    1. (g(b,c)<=s[i]),c比b优或一样
    2. (g(b,c)>s[i]),b比c优但是a比b优,所以a优

    所以,可以用队列维护一个下凸包,为何不是栈呢,这点想了好久,如果j比k优,j永远比k优,所以没用的就扔了。

    #include<bits/stdc++.h>
    #include<iostream>
    using namespace std;
    template<class T> inline bool read(T &x){
        x=0;register char c=getchar();register bool f=0;
        while(!isdigit(c)){if(c==EOF)return false;f^=c=='-',c=getchar();}
        while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
        if(f)x=-x;
        return true;
    }
    typedef long long ll;
    const ll MAXN=5e5+8,inf=0x3f3f3f3f,mod=1e9+7;
    int n,m;
    int s[MAXN],dp[MAXN],cnt;
    int que[MAXN],l,r;//队列  [l,r)
    inline int dy(int a,int b){return dp[a]+s[a]*s[a]-dp[b]-s[b]*s[b];}
    inline int dx(int a,int b){return 2*(s[a]-s[b]);}//a>b,如果不是这样,返回负数,不等式要变号
    inline void up(int i,int j){dp[i]=dp[j]+(s[i]-s[j])*(s[i]-s[j])+m;}//用j更新i
    int main() {
        while(read(n)&&read(m)){
            for(int i=1;i<=n;++i){
                read(s[i]);
                s[i]+=s[i-1];
            }
            l=r=0;
            que[r++]=0;
            for(int i=1;i<=n;++i){
                while(l<r-1&&dy(que[l+1],que[l])<=s[i]*dx(que[l+1],que[l]))l++;//直接l++,而不是零时变量
                up(i,que[l]);
                while(l<r-1&&dy(que[r-1],que[r-2])*dx(i,que[r-1])>=dy(i,que[r-1])*dx(que[r-1],que[r-2]))r--;
                que[r++]=i;
            }printf("%d
    ",dp[n]);
        }
        return 0;
    }
    

    每个i入队一次,出队最多一次,所以是O(n)

  • 相关阅读:
    client offset screen 的区别
    js中const,var,let区别
    jquery的选择器
    gulp
    JS 实现图片放大效果
    html单个标签实现跑马灯效果
    前端之HTML知识点整理
    各种纯css图标
    防止反复点击的思路
    .NET Memcached Client 扩展获取所有缓存Key
  • 原文地址:https://www.cnblogs.com/foursmonth/p/14155949.html
Copyright © 2020-2023  润新知