zoukankan      html  css  js  c++  java
  • HDU3507 Print Article

    Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
    Total Submission(s): 9301    Accepted Submission(s): 2893


    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.
     

    题意概括:有N个数字需要输出,输出过程中可以随意换行。每行需要付出常数M的额外代价。若一行中连续输出(只输出一个也算),则需要的代价依照上述公式计算。

        求代价最小值。

    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
     
    Author
    Xnozero
     
    Source
     
    Recommend
    zhengfeng

    很容易想到DP解决。

    设f[i]表示输出前i个数字的花费,则有转移方程$f[i]=min(f[i],f[j]+(sum[i]-sum[j])^2+M),0<j<i$

    n范围很大,按这个式子暴力动规会TLE,所以需要斜率优化。

    若有k满足0<k<j<i  ,且用k算比用j优(算出的花费更小),则有 $f[k]+(sum[i]-sum[k])^2+M<=f[j]+(sum[i]-sum[j])^2+M))$

    各种变形化简得到:$[(dp[j]+sum[j]*sum[j])-(dp[k]+sum[k]*sum[k])] / 2(sum[j]-sum[k]) <=sum[i]$

    设:$ y=dp[j]+sum[j]*sum[j] $  $x=2*sum[j]$

    可以得到斜率表达式:$(yj-yk)/(xj-xk) <= sum[i] $

    据此维护一个斜率逐渐增大的队列来dp,即可快速出解

     1  /**/
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<cstring>
     6 #include<algorithm>
     7 using namespace std;
     8 const int mxn=500020;
     9 int f[mxn];
    10 int sum[mxn];
    11 int q[mxn];
    12 int n,m;
    13 int up(int x,int y){//式子的分子 
    14     return (f[x]+sum[x]*sum[x])-(f[y]+sum[y]*sum[y]);
    15 }
    16 int down(int x,int y){//式子的分母 
    17     return 2*(sum[x]-sum[y]);
    18 }
    19 int dp(int x,int y){//dp值 
    20     return f[y]+(sum[x]-sum[y])*(sum[x]-sum[y])+m;
    21 }
    22 int main(){
    23     while(scanf("%d%d",&n,&m)!=EOF){
    24         int i,j;
    25         int hd=0,tl=0;
    26         sum[0]=0;f[0]=0;
    27         for(int x,i=1;i<=n;i++){
    28             scanf("%d",&x);
    29             sum[i]=sum[i-1]+x;
    30         }
    31         q[tl++]=0;
    32         for(i=1;i<=n;i++){
    33             while(hd+1<tl && up(q[hd+1],q[hd])<=sum[i]*down(q[hd+1],q[hd]))hd++;
    34             f[i]=dp(i,q[hd]);
    35             while(hd+1<tl && up(i,q[tl-1])*down(q[tl-1],q[tl-2])<=up(q[tl-1],q[tl-2])*down(i,q[tl-1]))tl--;
    36             q[tl++]=i;
    37         }
    38         printf("%d
    ",f[n]);
    39     }
    40     return 0;
    41 }
  • 相关阅读:
    hdu 4777 树状数组+合数分解
    hdu5635 BestCoder Round #74 (div.2)
    hdu 5636 搜索 BestCoder Round #74 (div.2)
    hdu 5637 BestCoder Round #74 (div.2)
    hdu4605 树状数组+离散化+dfs
    hdu4521 线段树+dp
    hdu3340 线段树+多边形
    孜孜不倦,必能求索;风尘仆仆,终有归途。
    增加、删除类文件或者在一个类中增加、删除方法时,是不能够热部署到服务上的。这时候需要停止服务器重新部署后再启动,就不会出现上面的提示了。
    为什么jdk1.8不支持sql.append,该如何解决
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/5704639.html
Copyright © 2011-2022 走看看