• 锯木厂选址


    这是我斜率DP第一个没有一遍AC的,原因是第一遍忘开long long了。

    这一题比较特殊,细心的同学一定发现了,递推式不带f。

    为了方便,设d数组的后缀和为sd[i]=sd[i+1]+d[i],设k数组的前缀和为sk[i]=sk[i-1]+k[i](k[i]即是题目中的w[i])

    设f[i]为第二个锯木厂选在i时的最小值,假设第一个锯木厂在j,从1~j-1运到j的和是k[p]*(sd[p]-sd[j]),p∈[1,n],从j+1~i-1运到i的和是k[p]*(sd[p]-sd[i]),p∈[j+1,i]。

    从i+1~n运到第三个锯木厂的和是k[p]*sd[p],p∈[i+1,n]。设k[p]*sd[p]的和为sum。

    那么整理一下此式为:f[i]=sum-sd[j]*sk[j]-sd[i]*sd[k]+sd[i]*sk[j],惊奇的发现不需要递推,可惜没有什么用。

    整理成一次函数式:sd[j]*sk[j]=sd[i]*sk[j]+sum-f[i]-sd[i]*sk[i]

    要让截距最大,且斜率sd[i]单调递减,那么考虑维护上凸包(不明白的一定要自己画图尝试!!)

    看代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int maxn=50000;
    int n,d[maxn],sd[maxn],sum,sk[maxn],k[maxn];
    int q[maxn],f[maxn];
    int yval(int a,int b){return sd[b]*sk[b]-sd[a]*sk[a];}
    int xval(int a,int b){return sk[b]-sk[a];}
    signed main(){
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%lld%lld",&k[i],&d[i]);
            sk[i]=sk[i-1]+k[i];
        }
        for(int i=n;i>=1;i--)
            sd[i]=sd[i+1]+d[i];
        for(int i=1;i<=n;i++)
            sum+=k[i]*sd[i];
        int l=1,r=1,ans=2147483647;
        for(int i=1;i<=n;i++){
            while(l<r&&yval(q[l],q[l+1])>=xval(q[l],q[l+1])*sd[i])l++;
            f[i]=sd[i]*sk[q[l]]-sd[q[l]]*sk[q[l]]+sum-sd[i]*sk[i];
            while(l<r&&yval(q[r-1],q[r])*xval(q[r],i)<=xval(q[r-1],q[r])*yval(q[r],i))r--;
            q[++r]=i;
            ans=min(ans,f[i]);
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    ES6 变量的解构赋值
    【js重学系列】new
    【js面试系列】手写常见js方法
    【js重学系列】this
    js-继承
    【js重学系列】数组高阶函数
    【js面试系列】数组去重
    云服务器部署项目-基本使用流程
    mongodb-基本使用
    移动端适配
  • 原文地址:https://www.cnblogs.com/syzf2222/p/12386817.html
Copyright © 2020-2023  润新知