zoukankan      html  css  js  c++  java
  • HDU-2829 Lawrence 【斜率优化DP】【四边形不等式优化】

    题目链接

    题意

    背景故事大概是说一战时一个英国间谍Lawrence要指挥突击队去炸毁奥斯曼帝国的一些铁轨。铁轨上有n个火车站,按线性排列,每个火车站上有一个权值,最后整个铁路的价值就是每一段联通铁路段上的火车站权值两两相乘的和加起来(联通段上只有一个车站就是0)。Lawrence有m次炸毁两个车站之间铁路的机会,求Lawrence最终可以使得这段铁路价值变成的最小值。

    分析

    转移方程易想出,设状态dp[i][j]为对于前i个车站的铁路来说,炸j次,能得到的最低价值,那么转移方程:

    dp[i][j]=min1ki(dp[k][j1]+prod[k+1][i])
    (j!=0)
    dp[i][0]=prod[1][i]

    其中prod[a][b]值a到b间两两相乘的和。至于prod[a][b]的算法:
    prod[k+1][i]=12((sum[i]sum[k])2(sq[i]sq[k]))

    其中sum为前缀和,sq为前缀平方和。
    那么代入转移方程中,移一下项,可以斜率优化,也可以四边形优化。
    注意这是二维的斜率优化,要注意更新的是哪个j对应的队列。

    AC代码

    //HDU-2829 Lawrence
    //AC 2017-2-26 15:10:03
    //DP, slope trick
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int maxn=1050;
    
    int n,m;
    long long sum[maxn],sq[maxn];
    long long dp[maxn][maxn];
    long long que[maxn][maxn];
    int head[maxn],tail[maxn];
    
    void init()
    {
        sum[0]=sq[0]=0;
        for(int i=0;i<=m;++i)
            tail[i]=head[i]=0;
        return;
    }
    
    int que_size(int j)
    {
        return tail[j]-head[j];
    }
    
    int get_front(int j)
    {
        return que[j][head[j]];
    }
    
    long long gety(int i,int j)
    {
        return sum[i]*sum[i]+sq[i]+2*dp[i][j];
    }
    
    long long getx(int j)
    {
        return sum[j];
    }
    
    int slope_1(int a,int b,int c,int j)
    {
        return gety(b,j)-gety(a,j)<=2*sum[c]*(getx(b)-getx(a));
    }
    
    int slope_2(int a,int b,int c,int j)
    {
        return (gety(b,j)-gety(a,j))*(getx(c)-getx(b))>
               (gety(c,j)-gety(b,j))*(getx(b)-getx(a));
    }
    
    void trail_head(int i,int j)
    {
        while(que_size(j)>=2)
        {
            if(slope_1(que[j][head[j]],que[j][head[j]+1],i,j))
                ++head[j];
            else
                break;
        }
        return;
    }
    
    void que_insert(int i,int j)
    {
        while(que_size(j)>=2)
        {
            if(slope_2(que[j][tail[j]-2],que[j][tail[j]-1],i,j))
                --tail[j];
            else
                break;
        }
        que[j][tail[j]++]=i;
        return;
    }
    
    int main()
    {
        while(scanf("%d %d",&n,&m)!=EOF&&n+m)
        {
            init();
            for(int i=1;i<=n;++i)
            {
                scanf("%lld",sum+i);
                sq[i]=sq[i-1]+sum[i]*sum[i];
                sum[i]+=sum[i-1];
            }
            for(int i=1;i<=n;++i)
            {
                dp[i][0]=(sum[i]*sum[i]-sq[i])/2;
                for(int j=1;j<=min(i-1,m);++j)
                {
                    trail_head(i,j-1);
                    int k=get_front(j-1);
                    dp[i][j]=-2*sum[i]*sum[k]+gety(k,j-1)
                             +sum[i]*sum[i]-sq[i];
                    dp[i][j]/=2;
                }
                for(int j=0;j<=min(i-1,m);++j)
                    que_insert(i,j);
            }
            cout<<dp[n][m]<<endl;
        }
        return 0;
    }
  • 相关阅读:
    揉碎HTTP编码过程,从此不乱码
    Eclipse与IDEA配置tomcat
    JavaWEB入门
    网络编程-socket
    Java
    Mysql存储过程 —— SEQUENCE的实现
    Java Servlet 2.5 设置 cookie httponly
    CountDownLatch和CyclicBarrier 区别
    ply python 图片压缩 图片裁剪 旋转
    各种正则大杂烩,正则手机,正则邮箱
  • 原文地址:https://www.cnblogs.com/DrCarlluo/p/6580571.html
Copyright © 2011-2022 走看看