hdu 2829 斜率DP 板子

http://acm.hdu.edu.cn/showproblem.php?pid=2829
题意:

在一条直线型的铁路上,每个站点有各自的权重num[i],每一段铁路(边)的权重(题目上说是战略价值什么的好像)是能经过这条边的所有站点的乘积之和.。然后给你m个炮弹,让你选择破坏掉m段铁路,使剩下的整条铁路的战略价值最小。

cost=i=lrVi(pre[r]pre[i1]Vi)=i=lrVi(pre[r]pre[i1])i=lrV2i

dp[i][j]表示到j为止的前面炸了i条路的得到最小总数
dp[i,j]=min(dp[i1,k]+cost)=(pre[i]pre[k])2(pre2[i]pre2[k])=

min(dp[i1,k]+pre[i]2+pre[k]22pre[i]pre[k]pre2[i]+pre2[k])

<script type="math/tex; mode=display" id="MathJax-Element-28"></script>
dp[i][j]=min(pre[i]2pre2[i]2pre[k]pre[i]+dp[i1][k]+pre2[k]+pre[k]2)

代码中部分代码的解释
2pr[k](k)
sq(pr[i])+pr2[i]+dp[i][1](b)
pr[i](x)

#include <bits/stdc++.h>
using namespace std;

#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define mp make_pair
#define cl(a) memset((a),0,sizeof(a))
#ifdef HandsomeHow
#define dbg(x) cerr << #x << " = " << x << endl
#else
#define dbg(x)
#endif
typedef long long ll;
typedef unsigned long long ull;
typedef pair <int, int> pii;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
const int mod=1000000007;
const double pi=acos(-1.0);
inline void gn(long long&x){
    int sg=1;char c;while(((c=getchar())<'0'||c>'9')&&c!='-');c=='-'?(sg=-1,x=0):(x=c-'0');
    while((c=getchar())>='0'&&c<='9')x=x*10+c-'0';x*=sg;}
inline void gn(int&x){long long t;gn(t);x=t;}
inline void gn(unsigned long long&x){long long t;gn(t);x=t;}
ll gcd(ll a,ll b){return a? gcd(b%a,a):b;}
ll powmod(ll a,ll x,ll mod){ll t=1ll;while(x){if(x&1)t=t*a%mod;a=a*a%mod;x>>=1;}return t;}
// (づ°ω°)づe★------------------------------------------------
const int maxn = 1005;
ll dp[maxn][maxn];


typedef pair <ll, ll> Line;
#define k first
#define b second
struct ConvexHull
{
    Line stk[maxn];
    int l, r;
    void init(){ l = r = 0; }
    //sz r - l  [l,r)

    bool cover(Line &a, Line &b, Line &c)
    {
        // line a and b cover line c
        return (a.k - b.k) * (b.b - c.b) >= (b.b - a.b) * (c.k - b.k);
        //  >= 下凸包 求最小值
        //  <= 上凸包 求最大值
    }

    void add(Line p)
    {
        while(r - l > 1 && cover(p,stk[r-2],stk[r-1]))r--;
        stk[r++] = p;
    }

    ll calc(ll x, Line l){ return l.k * x + l.b; }

    ll ask(ll x)
    {
        while(r - l > 1 && calc(x,stk[l+1]) <= calc(x,stk[l]))l++;
        return calc(x,stk[l]);
    }
}hull;

#undef k
#undef b

ll sq(ll x){ return x*x; }
ll pr[maxn], pr2[maxn];
ll v[maxn];
int n,m;
int main(){
#ifdef HandsomeHow
    freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
#endif
    while(true){
        gn(n);gn(m);
        if(n==0&&m==0)break;
        rep(i,1,n){
            gn(v[i]);
            pr[i]=pr[i-1]+v[i];
            pr2[i]=pr2[i-1]+sq(v[i]);
        }
        dp[0][0]=0;
        rep(i,1,n)dp[i][0]=sq(pr[i])-pr2[i];
        rep(_,1,m){
            hull.init();
            hull.add(mp(0,0));
            rep(i,1,n){
                if(i  <= _ + 1)
                    dp[i][_] = 0;
                else
                    dp[i][_] = hull.ask(pr[i]) - pr2[i] + sq(pr[i]);

                hull.add( mp( -2*pr[i],sq(pr[i]) + pr2[i] + dp[i][_-1] ) );
            }
        }

        printf("%lld\n",dp[n][m]/2);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值