zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Python eval 函数妙用
    502与504故障分析与解决方法
    [转]谈谈select, iocp, epoll,kqueue及各种网络I/O复用机制
    计算阶乘n!末尾0的个数
    C++中的Overload、Override和Overwrite
    C++中的空类与空结构体大小
    多线程编程之优先级翻转问题
    数据库原理之事务(二)
    数据库原理之事务(一)
    NoSQL之基础篇
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673492.html
Copyright © 2011-2022 走看看