• 一本通1614锯木厂选址


    1614:锯木厂选址

    时间限制: 1000 ms         内存限制: 32768 KB

     

    Description

     

    从山顶上到山底下沿着一条直线种植了n棵老树。当地的政府决定把他们砍下来。为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂。
    木材只能按照一个方向运输:朝山下运。山脚下有一个锯木厂。另外两个锯木厂将新修建在山路上。你必须决定在哪里修建两个锯木厂,使得传输的费用总和最小。假定运输每公斤木材每米需要一分钱。

     

    Input

     

    输入的第一行为一个正整数n——树的个数(2≤n≤20 000)。树从山顶到山脚按照1,2……n标号。接下来n行,每行有两个正整数(用空格分开)。第i+1行含有:wi——第i棵树的重量(公斤为单位)和 di——第i棵树和第i+1棵树之间的距离,1≤wi ≤10 000,0≤di≤10 000。最后一个数dn,表示第n棵树到山脚的锯木厂的距离。保证所有树运到山脚的锯木厂所需要的费用小于2000 000 000分。

     

    Output

     

    输出只有一行一个数:最小的运输费用。

     

    Sample Input

     

    9
    1 2
    2 1
    3 3
    1 1
    3 2
    1 6
    2 1
    1 2
    1 1

     

    Sample Output

     

    26

    数据范围玄学:n2可过,正解应该是O(n)的,所以姑且认为是106

    sol:斜率优化dp 有点像ZJOI2007仓库建设

    n2暴力几乎和上一道一样,就是稍微转化下,就把统计 j ~ i 的东西全部运到 i 需要的花费变成O(1)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=200005;
    const ll inf=0x7fffffffffff;
    int n;
    ll W[N],W_Qzh[N],Dis[N],Cost[N];
    ll dp_Last[N],dp[N];
    int main()
    {
        int i,j;
        R(n);
        Dis[1]=0;
        for(i=1;i<=n;i++)
        {
            W[i]=read();
            W_Qzh[i]=W_Qzh[i-1]+W[i];
            Dis[i+1]=Dis[i]+read();
            Cost[i]=Cost[i-1]+W[i]*Dis[i];
        }
        for(i=1;i<=n;i++)
        {
            dp_Last[i]=Dis[i]*W_Qzh[i]-Cost[i];
        }
        memset(dp,63,sizeof dp);
        for(i=2;i<=n;i++)
        {
            for(j=1;j<i;j++)
            {
                dp[i]=min(dp[i],dp_Last[j]+Dis[i]*(W_Qzh[i]-W_Qzh[j])-(Cost[i]-Cost[j]));
            }
        }
        ll ans=inf;
        for(i=2;i<=n;i++)
        {
            ans=min(ans,dp[i]+Dis[n+1]*(W_Qzh[n]-W_Qzh[i])-(Cost[n]-Cost[i]));
        }
        Wl(ans);
        return 0;
    }
    /*
    input
    9
    1 2
    2 1
    3 3
    1 1
    3 2
    1 6
    2 1
    1 2
    1 1
    output
    26
    */
    n^2暴力

    推导如下

    j<k<i
    --> dp_Last[j]+Dis[i]*(W_Qzh[i]-W_Qzh[j])-(Cost[i]-Cost[j])
    --> dp_Last[j]+Dis[i]*W_Qzh[i]-Dis[i]*W_Qzh[j]-Cost[i]+Cost[j] (S2)

    --> dp_Last[k]+Dis[i]*(W_Qzh[i]-W_Qzh[k])-(Cost[i]-Cost[k])
    --> dp_Last[k]+Dis[i]*W_Qzh[i]-Dis[i]*W_Qzh[k]-Cost[i]+Cost[k] (S1)

    若k比j优 则 S1<=S2
    dp_Last[k]-Dis[i]*W_Qzh[k]+Cost[k] <= dp_Last[j]-Dis[i]*W_Qzh[j]+Cost[j]
    (dp_Last[k]+Cost[k])-(dp_Last[j]+Cost[j]) <= Dis[i]*(W_Qzh[k]-W_Qzh[j])

    /*
    
        j<k<i
        --> dp_Last[j]+Dis[i]*(W_Qzh[i]-W_Qzh[j])-(Cost[i]-Cost[j])
        --> dp_Last[j]+Dis[i]*W_Qzh[i]-Dis[i]*W_Qzh[j]-Cost[i]+Cost[j]   (S2)
        
        --> dp_Last[k]+Dis[i]*(W_Qzh[i]-W_Qzh[k])-(Cost[i]-Cost[k])
        --> dp_Last[k]+Dis[i]*W_Qzh[i]-Dis[i]*W_Qzh[k]-Cost[i]+Cost[k]   (S1)
        
        若k比j优 则 S1<=S2
        dp_Last[k]-Dis[i]*W_Qzh[k]+Cost[k] <= dp_Last[j]-Dis[i]*W_Qzh[j]+Cost[j]
        (dp_Last[k]+Cost[k])-(dp_Last[j]+Cost[j]) <= Dis[i]*(W_Qzh[k]-W_Qzh[j])
        
    */
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=200005;
    const ll inf=0x7fffffffffff;
    int n;
    ll W[N],W_Qzh[N],Dis[N],Cost[N];
    ll dp_Last[N],dp[N],Que[N];
    //(dp_Last[k]+Cost[k])-(dp_Last[j]+Cost[j]) <= Dis[i]*(W_Qzh[k]-W_Qzh[j])
    inline bool Panduan(int j,int k,int i) //j<k<i
    {
        ll S1=(dp_Last[k]+Cost[k])-(dp_Last[j]+Cost[j]);
        ll S2=Dis[i]*(W_Qzh[k]-W_Qzh[j]);
        return (S1<=S2)?(1):(0);
    }
    inline bool Panduan_Rev(int j,int k,int i) //j<k<i
    {
        ll S1=((dp_Last[k]+Cost[k])-(dp_Last[j]+Cost[j]))*(W_Qzh[i]-W_Qzh[k]);
        ll S2=((dp_Last[i]+Cost[i])-(dp_Last[k]+Cost[k]))*(W_Qzh[k]-W_Qzh[j]);
        return (S1>=S2)?(1):(0);
    }
    int main()
    {
        int i,j;
        R(n);
        Dis[1]=0;
        for(i=1;i<=n;i++)
        {
            W[i]=read();
            W_Qzh[i]=W_Qzh[i-1]+W[i];
            Dis[i+1]=Dis[i]+read();
            Cost[i]=Cost[i-1]+W[i]*Dis[i];
        }
        for(i=1;i<=n;i++)
        {
            dp_Last[i]=Dis[i]*W_Qzh[i]-Cost[i];
        }
        int Head=1,Tail=1; Que[1]=0;
        for(i=1;i<=n;i++)
        {
            while(Head<Tail&&Panduan(Que[Head],Que[Head+1],i)) Head++;
            j=Que[Head];
            dp[i]=dp_Last[j]+Dis[i]*(W_Qzh[i]-W_Qzh[j])-(Cost[i]-Cost[j]);
            while(Head<Tail&&Panduan_Rev(Que[Tail-1],Que[Tail],i)) Tail--;
            Que[++Tail]=i;
        }
        ll ans=inf;
        for(i=2;i<=n;i++)
        {
            ans=min(ans,dp[i]+Dis[n+1]*(W_Qzh[n]-W_Qzh[i])-(Cost[n]-Cost[i]));
        }
        Wl(ans);
        return 0;
    }
    /*
    input
    9
    1 2
    2 1
    3 3
    1 1
    3 2
    1 6
    2 1
    1 2
    1 1
    output
    26
    */
    斜率优化
  • 相关阅读:
    nodejs+express安装
    C++操作MySQL大量数据插入效率低下的解决方法
    代码中出现一个类似空格的东西---不间断空格
    java使用compareTo报Comparison method violates its general contract 异常
    实现dev双柱图
    DB2登录示例数据库
    DB2 报错:CLI0111E 数值超出范围。 SQLSTATE=22003
    解决Android应用进入桌面后,再次点击APP抛异常的问题
    android studio 3.0 修改release生成的apk名称
    winfrom打包好的程序,安装错误代码1603
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10421086.html
Copyright © 2020-2023  润新知