CF 319C

题目:伐木工人用电锯伐木,一共需要砍n棵树,每棵树的高度为a[i],每次砍伐只能砍1单位高度,之后需要对电锯进行充电,费用为当前砍掉的树中最大id的b[id]值。a[1] = 1 , b[n] = 0,a[i]<a[i+1],b[i]>b[i+1]。问砍完所有的树的最小费用。

分析:由于b[n] = 0 , 所以很容易弄出一个O(n^2)的状态转移方程。

dp[1] = 0;
for(int i=2;i<=n;i++){
    dp[i] = INF;
    for(int j=1;j<i;j++)
        dp[i] = min(dp[i],dp[j]+b[j]*a[i]);
}

  

这种朴素的转移方程显然会TLE。

注意到以上的方程,其实就是1D1D模型(具体百度)。可以利用斜率进行优化。

斜率优化无非是:假设j<k,有以下关系:

dp[k]+b[k]*a[i] < dp[j]+b[j]*a[i]

由于b[k]<b[j]。

因此移项之后为:

(dp[k]-dp[j])/(b[j]-b[k])<a[i]

因此,我们可以根据斜率进行优化,具体可以看代码,这部分比较好懂

#include <set>
#include <map>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

#define debug puts("here")
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define foreach(i,vec) for(unsigned i=0;i<vec.size();i++)
#define pb push_back
#define RD(n) scanf("%d",&n)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w)
#define All(vec) vec.begin(),vec.end()
#define MP make_pair
#define PII pair<int,int>
#define PQ priority_queue
#define cmax(x,y) x = max(x,y)
#define cmin(x,y) x = min(x,y)
#define Clear(x) memset(x,0,sizeof(x))
#define lson rt<<1
#define rson rt<<1|1

/*

#pragma comment(linker, "/STACK:1024000000,1024000000")

int ssize = 256 << 20; // 256MB
char *ppp = (char*)malloc(ssize) + ssize;
__asm__("movl %0, %%esp
" :: "r"(ppp) );

*/

char IN;
bool NEG;
inline void Int(int &x){
    NEG = 0;
    while(!isdigit(IN=getchar()))
        if(IN=='-')NEG = 1;
    x = IN-'0';
    while(isdigit(IN=getchar()))
        x = x*10+IN-'0';
    if(NEG)x = -x;
}
inline void LL(ll &x){
    NEG = 0;
    while(!isdigit(IN=getchar()))
        if(IN=='-')NEG = 1;
    x = IN-'0';
    while(isdigit(IN=getchar()))
        x = x*10+IN-'0';
    if(NEG)x = -x;
}

/******** program ********************/

const int MAXN = 1e5+5;

int q[MAXN];
ll a[MAXN],b[MAXN];
ll dp[MAXN];

double g(int j,int k){
    return (dp[k]-dp[j])*1.0/(b[j]-b[k]);
}

int main(){

#ifndef ONLINE_JUDGE
	freopen("sum.in","r",stdin);
	//freopen("sum.out","w",stdout);
#endif

    int n;
    while(cin>>n){
        rep1(i,n)
            LL(a[i]);
        rep1(i,n)
            LL(b[i]);

        Clear(dp);

        int h = 0 , t = 0;
        q[++t] = 1;

        REP(i,2,n){
            while(h+1<t&&g(q[h+1],q[h+2])<a[i])
                ++ h;
            dp[i] = dp[q[h+1]]+a[i]*b[q[h+1]];
            while(h+1<t&&g(q[t],i)<=g(q[t-1],q[t]))
                -- t;
            q[++t] = i;
        }
        cout<<dp[n]<<endl;
    }

	return 0;
}

  

原文地址:https://www.cnblogs.com/yejinru/p/3348326.html