hdu 1300 Pearls(线性dp/斜率优化)

题意:给你n个物品的数量和价格,单个购买物品时数量加10(买一个花11个钱),连续购买多个时,数量总和加10,以结束物品单价为准(价格是单价递增的,是以最贵的计算,所以就是最后一个物品),求最小单价

思路:就是简单的n2dp,注意初始化为0x3f,而不是0,还有就是在选取第j个物品时要从0开始,这样可以少写一个从0转移单个的直接赋值的语句,斜率优化下次再更新

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=105;

int a[maxn],val[maxn],dp[maxn],pre[maxn];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        memset(dp,0x3f,sizeof(dp));
        scanf("%d",&n);
        pre[0]=0;
        for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&val[i]),pre[i]=pre[i-1]+a[i];
        dp[0]=0;
        for(int i=1;i<=n;i++){
            for(int j=0;j<i;j++){
                dp[i]=min(dp[i],dp[j]+(pre[i]-pre[j]+10)*val[i]);
            }
        }
        printf("%d
",dp[n]);
    }
    return 0;
}

 斜率优化:有点问题,下面队列维护的为下凸壳,为什么需要l+1<R

代码:

-----------------二更----------------

模仿bzoj 1010 hzw的单调队列写法,(ps:hzw写法中l首先赋值为1,r为0,que[++r]=0,这里r先进行++,在进行赋值,这样在写单调队列的时候就直接用que[r]作为队列末尾就行了,方便易思考)

下面讨论为什么维护下凸壳的原因,等待三更

#include <bits/stdc++.h>
using namespace std;
const int maxn=105;

int a[maxn],val[maxn],dp[maxn],pre[maxn];
int que[maxn],l,r;

double slop(int j,int k)
{
    return (dp[j]-dp[k])*1.0/(pre[j]-pre[k]);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        memset(dp,0x3f,sizeof(dp));
        l=1,r=0;
        scanf("%d",&n);
        pre[0]=0;
        for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&val[i]),pre[i]=pre[i-1]+a[i];
        dp[0]=0;
        que[++r]=0;
        for(int i=1;i<=n;i++){
            while(l<r&&slop(que[l],que[l+1])<=val[i])l++;
            int j=que[l];
            dp[i]=dp[j]+(pre[i]-pre[j]+10)*val[i];
            while(l<r&&slop(que[r],que[r-1])>slop(que[r],i)) r--;
            que[++r]=i;
        }
        printf("%d
",dp[n]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lalalatianlalu/p/8527546.html