• hdu3507Print Article(斜率)


    Problem Description
    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
    这里写图片描述
    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

    分析:
    第二道斜率优化,摸索出了一点套路

    说实话题目就看蒙了。。。
    题意:将序列a[n]分成若干段,每段的值为(∑a[i])^2 + M. 求序列的最小值

    做优化dp首先需要的就是状态转移方程

    f[i]表示到第i个数的最优值
    f[i]=min{f[j]+(sum[i]-sum[j])^2+m} (前一段最后一个数是j)

    假设 k < j < i
    f[j]的状态比k更优
    则一定有

    f[j]+(sum[i]-sum[j])^2+m < f[k]+(sum[i]-sum[k])^2+m
    f[j]+sum[j]^2-2*sum[i]*sum[j] < f[k]+sum[k]^2-2*sum[i]*sum[k]
    (f[j]+sum[j]^2)-(f[k]+sum[k]^2) < 2*sum[i]*(sum[j]-sum[k])
    移项,得

    ((f[j]+sum[j]^2)-(f[k]+sum[k]^2))/(2*(sum[j]-sum[k])) < sum[i]

    设y=f[]+sum[]^2,x=sum[]
    则原式=>
    y[j]-y[k]/x[j]-x[k] < sum[i]
    设g(j,k)=y[j]-y[k]/x[j]-x[k]
    g(j,k) < sum[i]
    说明f[j]的状态比f[k]更优(横坐标更大的更优)

    那我们能不能利用这个性质去掉一些状态呢
    假设 k < j < i
    若g(j,k)>g(j,i),那么j这个状态可以去掉
    证明:
    1.g(i,j) < sum[i],i比j更优
    2.g(i,j) >=sum[i],则g(j,k)>g(i,j)>=sum[i],j比i优而k比j更优

    这样我们一旦遇到了g(j,k)>g(j,i)就可以去掉j这种状态了,

    这样我们的状态转移可以变成:
    1.维护一个双端优先队列
    2.维护f,在队首取元素,若g(q[tou],q[tou+1])<=sum[i],tou–
    因为tou+1的状态更优,直到g(q[tou],q[tou+1])>sum[i],
    就用q[tou]更新f
    3.在队尾加入f[i],若g(i,q[wei])<=g(q[wei],q[wei-1]),wei–,
    (g(j,k)>g(j,i)就可以去掉j这种状态了),直到g(i,q[wei])>g(q[wei],q[wei-1]),加入i

    tip:

    注意初始状态:
    f[0]=0;
    f[1]=sum[1]*sum[1]+m; //f[1]=f[0]+(sum[1]-sum[0])^2+m
    wei=1; tou=0; q[wei]=1; q[tou]=0;

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    
    using namespace std;
    
    const int N=500005;
    int n,m;
    int q[N],tou,wei,sum[N],f[N];
    
    double xl(int x,int y)
    {
        return (double)((f[x]+sum[x]*sum[x])-(f[y]+sum[y]*sum[y]))/(double)(2*f[x]-2*f[y]);
    }
    
    void doit()
    {
        f[0]=0; f[1]=sum[1]*sum[1]+m;  //初始状态很重要 
        wei=1; tou=0;
        q[wei]=1; q[tou]=0;
        for (int i=2;i<=n;i++)
        {
            while (tou<wei&&xl(q[tou],q[tou+1])<=sum[i]) tou++;
            f[i]=f[q[tou]]+(sum[i]-sum[q[tou]])*(sum[i]-sum[q[tou]])+m;
            while (tou<wei&&xl(i,q[wei])<=xl(q[wei],q[wei-1])) wei--;
            q[++wei]=i;
        }
        printf("%d",f[n]);
    }
    
    int main()
    {
        while (~(scanf("%d%d",&n,&m)))
        {
            int u;
            for (int i=1;i<=n;i++) scanf("%d",&u),sum[i]=sum[i-1]+u;
            doit();
        }
        return 0;
    }
  • 相关阅读:
    MVC模式简单介绍
    Android AES加密算法及事实上现
    01背包问题
    C++继承经典样例
    [React] React Fundamentals: Using Refs to Access Components
    [React] React Fundamentals: Owner Ownee Relationship
    [React] React Fundamentals: State Basics
    [React] React Fundamentals: First Component
    [Javascript] Lodash: Refactoring Simple For Loops (_.find, _.findLast, _.filter)
    [Javascript] Create an Array concatAll method
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673492.html
Copyright © 2020-2023  润新知