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;
    }
  • 相关阅读:
    oo——第三单元总结
    oo第三单元总结
    【BUAA软工】提问回顾与个人总结
    【BUAA软工】HTTP协议前后端实现及实战北航云盘爬取
    【BUAA软工】软件案例分析
    【BUAA软工】结对编程作业
    【BUAA 软工个人项目作业】玩转平面几何
    【BUAA 软工博客作业】个人博客作业
    【BUAA 软工热身作业】继往开来,勇攀高峰
    BUAA-OO-第四单元总结——终章
  • 原文地址:https://www.cnblogs.com/DrCarlluo/p/6580571.html
Copyright © 2011-2022 走看看