zoukankan      html  css  js  c++  java
  • HDU1300 Pearls (斜率dp模板题)

    本题我们首先很容易可以列出朴素的状态和转移方程

    f[i][j],代表前i个分j次购买的最小值

    那么显然,这个值可以根据j-1次的所有结果更新而来,但这样的算法是n^2的,不过这题数据范围好像不太大

    因为我是专题训练,所以我直接用上了斜率优化的方法

    因为题目的转移方程是 f[i][x]=min(f[j][x-1]+max(p[j+1-i])*(s[i]-s[j]+10))

    值得高兴的是,因为题目所给的价格是递增的,所以其中的max项就是p[i],这样我们观察就能发现一些奇妙的地方

    我们假设k<j,  如果f[k][x-1]+max(p[k+1-i])*(s[i]-s[k]+10)>=f[j][x-1]+max(p[j+1-i])*(s[i]-s[j]+10)

    那么k显然是是不如j的,用代数法移项

    就变成了 f[j][x-1]-f[k][x-1]/s[j]-s[k]<=p[i]

    我们又发现p[i]是不断递增的,所以这个式子一旦满足则永远满足,因此可以从头部删除

    而根据凸包优化原理,我们也可以证明从尾部删除的正确性,这道题的代码就出来了

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<vector> 
    using namespace std;
    const int N=1100;
    int a[N];
    int q[N]; 
    int s[N];
    int p[N];
    int f[N][N];
    int getup(int j,int i,int x){
        return f[i][x-1]-f[j][x-1];
    }
    int getdown(int j,int i){
        return s[i]-s[j];
    }
    int getdp(int j,int i,int x){
        return f[j][x-1]+p[i]*(s[i]-s[j]+10);
    }
    int main(){    
        int t;
        cin>>t;
        while(t--){
            int n;
            cin>>n;
            memset(s,0,sizeof s);
            memset(f,0,sizeof f);
            int i;
            for(i=1;i<=n;i++){
                scanf("%d%d",&a[i],&p[i]);
                s[i]=s[i-1]+a[i];
            }
            for(i=1;i<=n;i++)
            f[i][0]=(s[i]+10)*p[i];
            int x;
            int tt=0;
            int hh=0;
            for(x=1;x<=n-1;x++){
                tt=0;
                hh=0;
                q[0]=x;
                for(i=x+1;i<=n;i++){
                    while(hh+1<=tt&&getup(q[hh],q[hh+1],x)<=p[i]*getdown(q[hh],q[hh+1]))
                    hh++;
                    f[i][x]=getdp(q[hh],i,x);
                    while(hh+1<=tt&&getup(q[tt-1],q[tt],x)*getdown(q[tt],i)>=getdown(q[tt-1],q[tt])*getup(q[tt],i,x))
                    tt--;
                    q[++tt]=i;
                }
            }
            int res=0x3f3f3f3f;
            for(i=0;i<n;i++){
                res=min(res,f[n][i]);
            }
            cout<<res<<endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    代理模式与Android
    图数据库 Titan 高速入门
    怎样编写支持命令行选项的程序
    协方差的意义
    我所理解的Spring AOP的基本概念
    Google搜索解析
    POJ 3311 Hie with the Pie floyd+状压DP
    JS怎样将拖拉事件与点击事件分离?
    C++语言笔记系列之十二——C++的继承
    Mac下Android配置及unity3d的导出Android
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12303835.html
Copyright © 2011-2022 走看看