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

    Print Article

     HDU - 3507 

    【题目标题】:

    打印文章

    给出N个单词,每个单词有个非负权值Ci,现在要将它们分成连续的若干段,每段的代价为此段单词的权值和的平方,还要加一个常数M,即。现在想求出一种最优方案,使得总费用之和最小。

    【输入格式】

    包含多组测试数据,对于每组测试数据。 第一行包含两个整数N和M(0<=N<=500000,0<=M<=1000)。 第2-N+1行为N个整数。

    【输出格式】

    输出仅一个整数,表示最小的价值。

    【样例输入】

    5 5
    5
    9
    5
    7
    5
    3 0
    1
    2
    3

    【样例输出】

    230
    14

    sol:题目中特意把n≤500000标红意思是说n2绝对凉凉
    对于我这种菜鸡,只会先把暴力打出来再看
    k
    对于前缀和Qzhi=∑ Ci
      i=1

    dp[i]=min(dp[i],dp[j]+(Qzh[i]-Qzh[j])2+m)
    似乎我只会这样就完了(题解大法好!!!)

    斜率优化dp
    dp[i]=dp[j]+Qzh[i]2-2*Qzh[i]*Qzh[j]+Qzh[j]2+m
    对于j<k<i,如果k比j要优
    则满足 dp[k]+Qzh[i]2-2*Qzh[i]*Qzh[k]+Qzh[k]2+m ≤ dp[j]+Qzh[i]2-2*Qzh[i]*Qzh[j]+Qzh[j]2+m
    消去一样的可得 dp[k]-2*Qzh[i]*Qzh[k]+Qzh[k]2
    ≤ dp[j]-2*Qzh[i]*Qzh[j]+Qzh[j]2
    移项可得 dp[k]+Qzh[k]2-dp[j]-Qzh[j]2
    ≤ 2*Qzh[i]*(Qzh[k]-Qzh[j])
    所以可知 当(j<k<i) dp[k]+Qzh[k]2-dp[j]-Qzh[j]2 ≤ 2*Qzh[i]*(Qzh[k]-Qzh[j])时 k 比 j 优
    设 G[j][k]表示 G[j,k]=((dp[k]+Qzh[k]2)-(dp[j]+Qzh[j]2))/(2*Qzh[i]*(Qzh[k]-Qzh[j]))
    当G[j][k]<=1 k优于j,否则j优于k (其实G[j][k]就是斜率)
    当(j<k<i) 当G[j][k]>=G[k][i],k就没用了

    /*
        //dp[i]表示输出到第i位的最小费用
        //因此很容易推出dp[i]=min(dp[i],dp[j]+(sum[i]-sum[j])^2+m)
        //但是复杂度为O(n^2),一定会超时,
                    
        //假设j<k,假设k优于j
        //dp[k]+(sum[i]-sum[k])^2+m<dp[j]+(sum[i]-sum[j])^2+m
        //G[j,k]=((dp[k]+sum[k]^2)-(dp[j]+sum[j]^2))/(2*sum[i]*(sum[k]-sum[j]))<=1时
        //假设成立,也就是k优于j,否则j优于k
        //当k1<k<k2时,G[k1,k]>=G[k,k2]时,k没有用处
    */
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=500005;
    int n,m;
    int Queue[N];
    ll Qzh[N],dp[N];
    #define Sqr(x) ((x)*(x))
    inline bool Pand(int j,int k,int i) //j<k<i
    {
        ll P1=dp[k]+Sqr(Qzh[k])-dp[j]-Sqr(Qzh[j]);
        ll P2=2*Qzh[i]*(Qzh[k]-Qzh[j]);
        return (P1<=P2)?(1):(0);
    }
    inline bool Pand_Rev(int j,int k,int i) //j<k<i
    {
        ll P1=(dp[k]+Sqr(Qzh[k])-dp[j]-Sqr(Qzh[j]))*(Qzh[i]-Qzh[k]);
        ll P2=(dp[i]+Sqr(Qzh[i])-dp[k]-Sqr(Qzh[k]))*(Qzh[k]-Qzh[j]);
        return (P1>=P2)?(1):(0);
    }
    int main()
    {
        int i,j;
        while(~scanf("%d%d",&n,&m))
        {
            for(i=1;i<=n;i++)
            {
                Qzh[i]=Qzh[i-1]+read();
            }
            int Head=0,Tail=0; Queue[0]=0;
            for(i=1;i<=n;i++)
            {
                while(Head<Tail&&Pand(Queue[Head],Queue[Head+1],i)) Head++;
                dp[i]=dp[Queue[Head]]+Sqr(Qzh[i]-Qzh[Queue[Head]])+m;
                while(Head<Tail&&Pand_Rev(Queue[Tail-1],Queue[Tail],i)) Tail--;
                Queue[++Tail]=i;
            }
            Wl(dp[n]);
        }
        return 0;
    }
    /*
    input
    5 5
    5
    9
    5
    7
    5
    3 0
    1
    2
    3
    output
    230
    14
    */
    View Cod
  • 相关阅读:
    Kmeans文本聚类系列(已经完成)
    提问的智慧
    公告:关于博客管理
    MSSQL语句备份
    贝叶斯分类专题
    利用Viterbi算法,二元词图分词系列
    从KL相对熵(relative entropy或 KullbackLeibler divergence,KL距离)看文本语义距离系列
    特征词选择算法对文本分类准确率的影响(五)
    新闻类网页正文提取系列
    特征词选择算法对文本分类准确率的影响(四)
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10393118.html
Copyright © 2011-2022 走看看