bzoj1096: [ZJOI2007]仓库建设 斜率优化dp

https://www.lydsy.com/JudgeOnline/problem.php?id=1096

中文题意不说了,

dp【i】表示从1到i所有产品都能放,而且第i个地方一定建仓库的最小费用,转移方程dp[i]=min(dp[j]+Σ(j<k<=i)x[i]-x[k])*p[k](1<=j<i)

用sump表示p的前缀和,用sumpx表示p*x的前缀和,转移方程可变成dp[i]=dp[j]+x[i]*(sump[i]-sump[j])-(sumpx[i]-sumpx[j])

dp[i] + x[i] * sump[j] = dp[j] + x[i] * sump[i] - (sumpx[i]-sumpx[j])

b       +   k   *    x        =    y

因为x【i】递增所以可以利用斜率优化,

/**************************************************************
    Problem: 1096
    User: walfy
    Language: C++
    Result: Accepted
    Time:2528 ms
    Memory:55980 kb
****************************************************************/
 
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)
 
using namespace std;
 
const double g=10.0,eps=1e-12;
const int N=1000000+10,maxn=123456+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
 
ll xx[N],p[N],c[N],sumpx[N],sump[N],q[N],dp[N];
inline ll x(int j)
{
    return sump[j];
}
inline ll y(int j)
{
    return dp[j]+sumpx[j];
}
inline double slope(int a,int b)
{
    return (y(b)-y(a))/(x(b)-x(a));
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&xx[i],&p[i],&c[i]);
    for(int i=1;i<=n;i++)
    {
        sump[i]=sump[i-1]+p[i];
        sumpx[i]=sumpx[i-1]+p[i]*xx[i];
    }
    int head=1,last=1;q[last]=0;
    for(int i=1;i<=n;i++)
    {
        while(head<last&&slope(q[head],q[head+1])<xx[i])head++;
        int te=q[head];
        dp[i]=dp[te]+xx[i]*(sump[i]-sump[te])-sumpx[i]+sumpx[te]+c[i];
        while(head<last&&slope(q[last-1],q[last])>slope(q[last],i))last--;
        q[++last]=i;
//        printf("%d %lld\n",te,dp[i]);
    }
    printf("%lld\n",dp[n]);
    return 0;
}
/***********************
 
***********************/
View Code

 

(斜率优化的套路:有一项是关于x的函数乘上关于y的函数,然后关于x项的函数是单调的,其他项都是只包含一个(x或y)的函数)

posted @ 2018-04-27 22:58  walfy  阅读(164)  评论(0编辑  收藏  举报